All guidesIntegration

Test Webhooks with Outworx — Capture, Sign, Replay

A unique capture URL catches incoming webhooks in real-time. Send-test fires signed payloads at any handler. Replay any captured request to a different URL. The HMAC verifier covers Stripe, GitHub, Shopify, Slack, and 6 more providers — all browser-side, secret never leaves your machine.

April 28, 20267 min read

Webhooks are the hardest part of an API to debug. They're asynchronous, they fire from someone else's server, and the only signal you get when something goes wrong is a customer complaint days later. The usual loop — sender → your handler → silent failure — leaves you reverse-engineering a black box.

Outworx Docs ships a webhooks playground that turns that loop into something you can see, replay, and verify. A unique capture URL catches incoming requests in real-time. Send-test fires signed payloads at any handler. Replay re-runs a captured request against a different URL. And the HMAC verifier matches signatures from ten different webhook providers — Stripe, GitHub, Shopify, Square, Linear, HubSpot, Zoom, Zendesk, Slack — entirely in your browser.

This guide walks the whole flow: capturing a real webhook, replaying it against your local handler, sending test events, and verifying signatures.

Prerequisites

  • An Outworx Docs account (free signup includes 5 webhook inboxes)
  • Something that emits webhooks — Stripe, GitHub, your own service in test mode

You don't need a project, a spec, or any prior setup. Webhooks is standalone.

Step 1: Create an inbox

Go to /webhooks in the dashboard and click + New inbox. Give it a label like "Stripe staging" — only you see it. Linking to a project is optional and we'll skip it for now.

You'll land on a page with a prominent capture URL:

https://docs.outworx.io/api/inbox/2NX_7mCiC46d.......

Click Copy. This is the only auth on the inbox — anyone with the URL can post to it, so treat it like a webhook signing secret.

Step 2: Point a sender at it

Paste the URL into Stripe's webhook configuration (Dashboard → Developers → Webhooks → Add endpoint), or GitHub's repo webhooks settings, or whatever sender you're debugging. Send a test event from the sender's UI.

The capture appears in the dashboard's live stream within ~200ms — no refresh needed. We use Postgres logical replication via Supabase Realtime, so every authenticated browser tab subscribed to that inbox sees inserts the moment they happen.

Click any captured row to open the inspector. You get the full method + path, the source IP and ASN, every header (cookies stripped for safety), and the body pretty-printed if it's JSON / XML / form-encoded.

Step 3: Verify the signature

Most webhook senders sign their payloads. The Outworx HMAC verifier handles ten common schemes plus raw HMAC variants:

  • Stripe (v1, hex)
  • GitHub (sha256 + legacy sha1, hex)
  • Slack (v0, hex, with timestamp basestring)
  • Shopify (sha256, base64)
  • Square (sha256 over URL + body, base64)
  • Linear (sha256, hex)
  • HubSpot (v3, sha256 over method + URI + body + timestamp, base64)
  • Zoom (v0, sha256, hex, with timestamp basestring)
  • Zendesk (sha256 over timestamp + body, base64)
  • Outworx (our own Send-test signatures)
  • Raw HMAC-SHA1 / 256 / 512 in hex or base64

The verifier auto-detects the right scheme from the captured headers. Open a capture, expand "Verify signature (HMAC)", paste your signing secret, click Verify. Math runs in WebCrypto in your browser — your secret never crosses our network.

If the math passes, you also get a staleness check: schemes with timestamps (Stripe, Slack, HubSpot, Zoom, Zendesk) flag signatures older than 5 minutes, since most senders reject those as a replay defence.

Step 4: Replay against your handler

Found a malformed payload that broke production? Reproducing it normally means asking the sender to fire another one — Stripe doesn't make that easy. Outworx solves this with one click.

Hover the captured row, click Replay. The Send-test modal opens with the original body and headers pre-filled. Paste your handler URL (or https://abc.ngrok.io/webhooks for a local handler), optionally add your signing secret, and fire. We sign with HMAC-SHA256 in Stripe-v1 format under X-Outworx-Signature: t=<unix>,v1=<hex> so your handler can verify with the standard library it already uses.

Replays drop the original sender's signature header — the math wouldn't verify against your secret anyway, and we add X-Outworx-Replay: true so a paranoid handler can refuse replays if it wants.

Step 5: Send test events without waiting for the sender

The Send-test modal isn't just for replays. From /webhooks, click Send test to fire any payload at any URL:

  • Method: POST, GET, PUT, PATCH, or DELETE
  • Custom headers: Authorization, X-Webhook-Source, etc.
  • Signing secret: optional HMAC-SHA256
  • Body: paste raw JSON, or pre-fill from a spec event

If your project's OpenAPI spec includes the OpenAPI 3.1 webhooks: block, those events show up under /webhooks?section=events with per-event Send buttons that pre-fill payloads from the schema. One click and you've fired a sample invoice.paid at your handler.

Lock the inbox down for production traffic

The default inbox is open — anyone with the URL can post. That's the point during exploration. When you're ready to point real traffic at it, open Security in the inbox toolbar and turn on any combination of the three layers:

  • HMAC signature — pick a scheme (Outworx, Stripe, GitHub sha256/sha1, Slack, Shopify, Linear, Zendesk, or Custom HMAC where you set the header name, algorithm, encoding, and prefix), paste the shared secret, and the receiver will reject anything missing or mismatched with 401. Schemes that sign a timestamp also get replay protection — configurable tolerance, default 5 minutes.
  • HTTP Basic auth — username + password gate; missing or wrong credentials get 401 + WWW-Authenticate so well-behaved senders prompt for the right ones.
  • Source IP allowlist — paste IPv4 / IPv6 CIDR ranges, one per line. Off-network requests get 403. Useful for providers that publish their egress IPs (Stripe, GitHub).

Each layer is independent. Replays auto-sign with the inbox's stored secret using the configured scheme, so a locked-down inbox accepts its own replays without you having to re-paste the secret. Secrets and passwords never round-trip to the browser — the dialog shows a "leave blank to keep" affordance so saving other settings doesn't expose the stored value.

Localhost and tunnels

Outworx runs in the cloud and can't reach localhost on your machine. The Send-test modal shows a tunnel hint when it detects a localhost URL:

npx ngrok http 3000

Or cloudflared tunnel --url http://localhost:3000, or npx localtunnel --port 3000. Paste the resulting public URL into Send-test.

When you're running the Outworx app itself on localhost in dev mode, we auto-allow loopback addresses — no tunnel needed. Production is HTTPS-only with the SSRF guard fully active.

Plan limits

Free includes:

  • 5 inboxes
  • 500 captures received in any rolling 7-day window
  • 100 sends/day
  • 7-day retention

Pro: 25 inboxes, 10,000 captures / 30 days, 5,000 sends/day, 30-day retention.

Business: unlimited everything, 90-day retention.

The capture cap is enforced via an append-only ledger that survives "Clear all" — so a malicious user can't reset their quota by clearing inboxes. Senders that hit the cap receive HTTP 429 with Retry-After until ledger entries age out.

What this replaces

If you were using webhook.site, ngrok inspect, or a tab full of console.log statements in your handler — Outworx Webhooks is the integrated version. Capture + replay + signature verification all in one workspace, with plan limits sized for real production debugging instead of a forced upgrade after the third capture.

The capture URL is yours forever (or until you rotate it). The signing secret is yours and never crosses our network. Everything else — the schemas, the docs, the AI chat, the MCP server — is right next door if you need it.

Open /webhooks in your dashboard and create your first inbox. The whole flow is under thirty seconds.

Ship your API docs in under a minute.

Upload your OpenAPI, Swagger, or GraphQL spec and get beautiful hosted docs with AI chat and a per-project MCP server — free forever for 2 projects.