The Webhook Payload Generator produces realistic event payloads in the shapes used by popular services, so you can test webhook handlers, parsers, and integration logic without wiring up real accounts or waiting for live events.
How it works
Each service has its own builder that follows the documented payload structure:
- Stripe wraps a
data.objectinside the standard event envelope withid,type,created, andlivemode: false. - GitHub produces
push,pull_request,issues, orstarevents with arepository,sender, and a 40-character commit SHA. - Shopify emits order, product, customer, or checkout objects with
line_items,total_price, and acustomer.
IDs use each service’s prefixes and formats (for example evt_, cus_ for Stripe, a hex SHA for GitHub), and amounts, timestamps, and identifiers are randomised on every generation.
Why payload shape matters more than values
A webhook handler typically does two things with a payload: it checks the type (or topic header) to decide what action to take, and it destructures specific fields to read values. Both of these fail silently if the shape is wrong, even when the values are present.
This generator reproduces the documented shapes for each service so that shape-dependent destructuring works correctly. For example:
- A Stripe
payment_intent.succeededhandler expectsevent.data.object.amount— the value is nested two levels inside the event envelope. A handler that readsevent.amountdirectly would work on a flat test object but fail on a real Stripe event. - A GitHub
pull_requesthandler expectspayload.pull_request.head.sha— the SHA is nested underpull_request, not at the top level. A flat mock SHA would not reveal this. - A Shopify
orders/createhandler expectspayload.line_itemsto be an array withpriceandquantityfields per item.
Generating from this tool exposes shape bugs that a hand-written flat mock would hide.
Signature verification and why these fail it
Real Stripe webhooks include a Stripe-Signature header built from the payload bytes and your webhook secret using HMAC-SHA256. Because this generator does not know your secret, the generated payload will fail signature verification if you pass it through your normal verification middleware.
This is intentional. When testing the parsing path of a handler — what happens after verification succeeds — you should bypass or stub the signature check. When testing the verification path itself, you need real signing secrets and cannot use pre-generated payloads. The two concerns are best tested separately.
A common pattern is to write two test layers: an integration test that sends a correctly-signed payload to a real endpoint (using the Stripe CLI’s stripe trigger command or GitHub’s delivery re-send), and a unit test that passes a generated payload directly to the handler function, skipping the HTTP layer entirely.
Service-specific notes
Stripe. The livemode: false flag is set on all generated payloads so they are clearly synthetic. The type field uses real Stripe event type names. Payment amounts are in the currency’s smallest unit (for example cents for USD, pence for GBP).
GitHub. Commit SHAs are 40-character hex strings. The ref field follows the refs/heads/branch-name format. pusher and sender are separate objects, which is a common gotcha for handlers that conflate them.
Shopify. Line item prices are strings, not numbers — Shopify uses decimal strings for currency. A handler that coerces price with parseInt will silently lose cents.
Practical tips
- Use the generated JSON as a request body in
curlor your test runner to exercise the parsing path of a handler. - Switch services to confirm your router branches correctly on the event type or the
X-GitHub-Event/X-Shopify-Topicheader. - Everything is local with no API key, so generate freely during rapid iteration.