Stripe webhooks, as delivered.
Every event Stripe sends to this site is signature verified, stored, and shown here exactly as it arrived. Buy something in the agentic commerce shop and the resulting event appears in this feed.
Stripe posts to an endpoint configured on the account, signed with a secret belonging to that endpoint rather than to the account. Each event is checked against it before being stored. Nothing is normalised or renamed. Field names, nesting and value types are Stripe's own, and the envelope around the object is kept rather than unwrapped.
Showing the 50 most recent events, newest first. Select a row to see the body as delivered.
Reading the feed
The name in the second column is Stripe's type, a dotted path like checkout.session.completed. Unlike Adyen, there is no separate success field. The outcome is part of the name: a failure arrives as payment_intent.payment_failed rather than as a payment event carrying a false flag. That removes a whole class of bug, at the cost of a much longer list of names to know.
The third column is the nearest thing Stripe has to a status, and it is not one field. A Checkout Session carries payment_status, a PaymentIntent carries status, and several object types carry neither. So that column is filled from whichever exists, which is itself worth noticing: there is no single place to look to ask whether it worked.
Two identifiers, and they are not interchangeable
Every delivery has an id beginning evt_, which identifies the event, and an object inside data.object with its own id, which identifies the thing that happened. The last column shows the second one, because that is what joins an event to a payment.
This matters for deduplication. Stripe redelivers on failure, and a redelivery carries the same evt_ id. Two genuinely different events about the same payment carry different evt_ ids and the same object id. Deduplicating on the wrong one either drops real events or processes the same one twice.
The envelope is part of the payload
Expanding a row shows the whole event, not just the object. That envelope carries livemode, api_version and pending_webhooks, and the first two are worth attention. api_version is pinned per endpoint, so the same account can deliver differently shaped objects to two endpoints at once. An integration that was written against the Dashboard's current version and then tested against an older pinned endpoint will disagree with itself in ways that look like a parsing bug.
Order is not guaranteed
Stripe does not promise events arrive in the order they occurred, and retries make that worse rather than better. A handler that assumes a session completed before its payment intent succeeded will be right most of the time, which is the most difficult kind of wrong to find. The safe pattern is to treat each event as a statement about current state and fetch the object if the answer matters, rather than reconstructing a sequence from arrival order.
Signature verification uses the raw body
The Stripe-Signature header is computed over the exact bytes received. Any JSON middleware that parses before verification destroys the thing being verified, and re-serialising the parsed object does not reproduce it, since key order and whitespace will differ. On this server the raw body is captured during parsing and kept for that check, which is also what the Adyen HMAC check needs.
A bad signature here returns 400, deliberately. Stripe treats that as a failed delivery and retries, which is the right behaviour if a secret was briefly wrong, and it gives up rather than retrying forever on a genuinely invalid one.
Questions, feedback, or work in payments?
I'm always happy to hear from fellow payments people.
Personal project by Elie Joseph. Not affiliated with, endorsed by, or officially connected to any payment service provider. All product and company names, logos and brands referenced on this site are property of their respective owners. Playgrounds run against test environments only. No real payments are processed. Use only test data. Never enter real card numbers, real personal information, or any genuine payment details on this site or in any linked test environment.