Webhook payload generator (sample events for 6 providers)

Free webhook payload generator: pick Stripe, GitHub, Shopify, Slack, Discord or Twilio and an event type, get a realistic sample payload, then copy it or send it to your webhooks.sh bin as a test request. Generated in your browser; nothing leaves the page unless you send it.

Hand-writing webhook payloads gets old fast — you forget a field your handler needs, or the shape is subtly off and you debug your own fixture instead of your code. Pick a provider and an event below and get a realistic, trimmed payload you can copy or fire straight at an endpoint. Everything is generated 100% in your browser; nothing leaves this page unless you hit "Send test request", which goes only to the URL you paste.

Why testing with realistic payloads matters

Most webhook handlers don't just check type — they reach deep into the payload: data.object.customer on a Stripe event, repository.full_name on a GitHub delivery, MessageStatus on a Twilio callback. A fixture of {"foo": "bar"} sails through your unit test and then the first real delivery 500s because a nested field you assumed would exist is named differently. Testing with payloads that mirror what the provider actually sends catches that class of bug before production does.

Real payloads also carry the envelope fields your infrastructure depends on: event ids for deduplication (evt_… on Stripe, X-GitHub-Delivery on GitHub), timestamps for ordering and replay checks, and provider-specific wrappers (Slack nests everything under event; Discord signals its intent through the numeric type field). Trimming is fine — providers send far more than you need — but the fields you keep should have the real names, real nesting, and plausible formats.

Fields handlers typically depend on

  • Stripe: type for routing, id for idempotency, data.object for the actual resource (its shape depends on the object type, not the event name). See the Stripe playbook.
  • GitHub: action is the one people forget — the same event (pull_request) fires for opened, closed, synchronize and a dozen more actions. repository and sender anchor everything else. See the GitHub playbook.
  • Shopify: the topic arrives in the X-Shopify-Topic header, not the body — the body is just the resource. orders/create and orders/paid look nearly identical except financial_status. See the Shopify playbook.
  • Slack: type at the top level decides everything — answer url_verification challenges by echoing challenge, and route event_callback on event.type. See the Slack playbook.
  • Discord: type: 1 (PING) must get a PONG back or Discord never verifies your endpoint; slash commands arrive as type: 2 with the command name under data.name.
  • Twilio: no JSON at all — callbacks are form-encoded POST bodies with MessageSid, MessageStatus, From/To. Your parser needs urlencoding, not JSON.

Sending it somewhere

The send button posts the payload to your bin with the provider's real content type (JSON, or form-encoded for Twilio) and shows what the bin answered: the status code and the delivery id. Paste the capture URL of a free bin (it ends in .webhooks.page; get one at view.webhooks.page) or of a paid endpoint (.webhooks.host). A bin's view link works too.

It only sends to webhooks.sh bins and endpoints. To hit your own server or staging, copy the payload and post it with curl. The page doesn't sign requests either: to test signature logic, verify a captured request with the HMAC signature verifier or use the provider's own CLI.

To drive your local app with these payloads, pair the generator with a tunnel or a provider CLI — testing webhooks locally walks through the full loop, and testing without ngrok compares the free options.

Common mistakes

  • Fixtures that drifted. Providers add and rename fields; regenerate samples from real deliveries (a bin shows you ground truth) instead of trusting a fixture committed two years ago.
  • Wrong content type. Posting JSON to a Twilio-style handler (or form fields to a JSON one) tests nothing — match the provider's real encoding.
  • Testing only the happy path. Fire the deletion, the failure, and the duplicate too. Retries mean your handler will see the same event id more than once.
  • Stopping at the 200. A 200 only proves the request arrived. Open the capture and check the body and headers your handler will actually parse.

Last updated

Try it in 10 seconds.

Create a free bin at view.webhooks.page — no signup, no install. Point your sender at the URL and watch requests land live. Bins expire after 48 hours.