CommerceHook

Stripe

Stripe is the one platform CommerceHook supports where the vendor’s own webhook tooling is good. The Dashboard shows event deliveries, Workbench resends them, and the CLI forwards to localhost. None of that is worth replacing.

What CommerceHook adds is the part Stripe cannot see: the storefront webhooks that fired for the same basket, in the same timeline, kept longer than Stripe’s resend windows reach.

Which key to use

Stripe is also the one platform where you can hand over a key scoped to exactly this job. Create a restricted key at dashboard.stripe.com/apikeys/create with:

  • Webhook Endpoints: write
  • ConnectAccounts: read (so we can confirm which account the key belongs to and label it for you)

The second one is filed under Connect, which reads as though it only concerns other people’s accounts under a platform. It does not. It is the permission that lets a key read the account it belongs to, and it is the only row on that page that grants that. Tick it even if you have never touched Connect. There is no plain “Account” row to look for.

That key can create and update webhook endpoints and read your account name. It cannot move money, read customers, or issue refunds.

A full secret key (sk_test_, sk_live_) works too, and the register panel accepts it with a nudge rather than a refusal. A publishable key (pk_) is rejected outright: it is the key meant for browsers, it cannot manage webhooks, and it sits directly beside the others on the same page, which is why pasting it is the easy mistake.

Test and live keys are separate credentials. The prefix says which, so you are never asked to choose a mode; save both and each registers into its own world.

Registering through CommerceHook

Open an endpoint, press Register, choose the Stripe tab, paste the key and tick the events you want. Stripe takes the whole list on a single webhook endpoint object, so one registration covers everything you ticked.

Two things follow from that:

  • The signing secret arrives with the endpoint. Stripe returns it at creation, so registering through us means we hold it without you ever copying it. Every delivery then shows a tick or a cross.
  • Registering again updates rather than duplicates. Stripe allows 16 webhook endpoints per account, and the panel would rather spend none of them than add a sibling. If we already created an endpoint for this URL, the button changes to say so.

The event picker is a curated commerce list: payments, checkout, customers, subscriptions, invoices, refunds and disputes, payouts, products and prices. Stripe’s full enum runs to several hundred entries across Issuing, Terminal, Climate and more, which nobody wants to scroll. If you want the lot, tick Everything. That sends Stripe’s own * wildcard, so it keeps meaning everything as Stripe adds events.

Registering in the Stripe Dashboard instead

You can also just paste your CommerceHook URL into Stripe’s own webhook settings. Deliveries arrive and are captured exactly the same way.

The one thing that cannot work by itself is signature verification: we never see the secret Stripe generated, so every delivery reads “unsigned”. Fix that by copying the endpoint’s Signing secret from the Stripe Dashboard into the register panel, under “Registered in the Stripe Dashboard instead?”. It is stored encrypted and flagged as externally managed, and verification then behaves identically.

How signatures are checked

Stripe signs {timestamp}.{raw body} with HMAC-SHA256 and sends the result hex-encoded in the Stripe-Signature header. We store payloads byte for byte, so verification runs against exactly what arrived.

Three details worth knowing:

  • Secret rolls are handled. During Stripe’s 24-hour overlap a delivery carries two signatures. Either matching is a pass.
  • v0 signatures are ignored, as Stripe instructs. Ordinary deliveries do carry one alongside the v1, so this is not a rare case: it is every delivery. Only v1 is checked, because treating an older scheme as valid is how a downgrade gets in.
  • Timestamps are shown, not enforced. A verified delivery is what Stripe sent, whenever it was sent. We show the signing time beside the verdict and leave the judgement to you, because an inspector that refused to display an old-but-genuine delivery would be hiding evidence.

If a delivery arrives for an endpoint we hold no secret for, the verdict is blank rather than a cross. Saying “mismatch” about a secret we never had would be a lie.

Every Stripe object id announces its own type, so the inspector links a payment, customer, invoice or subscription straight into the Dashboard, and follows the ids a payload cross-references: an invoice event also offers its customer and its subscription. Links respect the delivery’s own livemode, so test events go to the test Dashboard.

Each event also offers the curl that retrieves the object, with your key left as a shell variable.

Event destinations (v2)

Stripe’s newer v2 event destinations deliver thin events, which carry identifiers rather than a full object snapshot. CommerceHook registers v1 webhook endpoints only. If you point a v2 destination at a CommerceHook URL by hand, deliveries are still captured, still badged as Stripe, and still verified against a stored secret; they simply carry no object to deep link, because a thin event does not include one.

Limits worth remembering

  • 16 webhook endpoints per Stripe account. If you hit it, delete one at dashboard.stripe.com/webhooks.
  • Retention is your plan’s: 24 hours on Free, 90 days on Pro. Stripe’s own resend reaches 15 days from the Dashboard and 30 from the CLI, so Pro is the longer window of the two.