Websites · Glossary

What is a Stripe webhook?

A Stripe webhook is an HTTPS request Stripe sends to an address on your site whenever something happens in your account, such as a completed checkout, a refund or a failed subscription payment. Each request carries an event in JSON and a Stripe-Signature header, so your site can confirm the message came from Stripe before it marks an order paid.

A webhook is how a site learns the truth about a payment. The customer's browser can close, lose signal or be faked, but Stripe's signed event arrives either way, and the site acts on that.

· Co-founder

4 min read · Published

Stripe events a small business site commonly handles
EventWhen Stripe sends itWhat the site usually does
checkout.session.completedA customer finishes a Checkout SessionMark the order paid, or wait for async payment if it is not yet paid
checkout.session.async_payment_succeededA delayed payment method clearsMark the order paid and start fulfilment
charge.refundedA charge is refunded in full or partMark the order refunded and adjust stock
customer.subscription.updatedA subscription changes plan or statusUpdate the member's tier or access
invoice.payment_failedA subscription renewal failsFlag the member and prompt them to update their card

What a webhook is

A webhook turns the usual direction of an API around. Instead of your site asking Stripe for news, Stripe calls your site. You register an endpoint, an HTTPS address on your server or function, and choose which event types to receive. When one happens, Stripe sends a POST request with a JSON event object describing it. Stripe signs each request with a secret only you and Stripe know, the endpoint's signing secret starting whsec_, and puts the signature in the Stripe-Signature header.

How a site handles one

The endpoint reads the raw request body, verifies the signature with the signing secret and rejects anything that fails, which stops anyone faking a paid order by calling the address themselves. It then reads the event type and acts: for checkout.session.completed it looks up the order by the session's id or metadata and marks it paid. It returns a 2xx status quickly, before slow work such as emails, because Stripe treats slow or failed responses as undelivered. In live mode Stripe retries failed deliveries with backoff for up to three days, so the handler must be idempotent: processing the same event twice must not ship two parcels.

When it matters

Any site that takes money online needs one. The page a customer lands on after paying is not proof of payment; the customer might close the tab first, or a delayed payment method such as a bank debit might clear days later. Subscriptions need webhooks even more, because renewals, failed payments and cancellations happen while nobody is on the site. Refunds made in the Stripe dashboard also only reach the site's order records through a webhook.

Common mistakes

Marking orders paid from the success page's URL instead of the webhook. Parsing the JSON before verifying the signature, so the raw body no longer matches and every check fails. Skipping verification altogether. Doing slow work before responding, so Stripe times out and retries. Not handling duplicates. Listening for every event type when four or five are needed. Using the test mode signing secret in live mode. And forgetting that events can arrive out of order, so a refund might be processed before the payment it refers to.

Where it shows up in OneCraft

OneCraft sites take payments through a payments broker: Stripe Checkout as a direct charge on the owner's own connected Stripe account, for one off orders, subscriptions from a plans table and the Stripe billing portal. Prices are read from the site's own database, never from the browser, and a webhook marks each order paid or refunded. Stripe is connected in account Settings, Payments. The platform fee is 2% on Starter, 1% on Pro and 0.5% on Pro+, with Stripe's fees on top, and the free plan cannot take payments.

Questions people ask

What is the difference between a webhook and an API call?

An API call is your site asking Stripe for something, such as creating a Checkout Session. A webhook is Stripe telling your site that something happened, without being asked. Most payment flows use both: an API call to start the payment and a webhook to learn the outcome.

How do I test Stripe webhooks?

Use test mode and the Stripe CLI, which can forward events to a local address and trigger sample events such as checkout.session.completed. The dashboard's event destination page shows every delivery attempt, its response code and the request body, which helps when an endpoint returns errors.

What happens if my webhook endpoint is down?

Stripe keeps the event and retries delivery. In live mode it retries with increasing gaps for up to three days, and you can resend events manually from the dashboard. Orders made during an outage stay unpaid on your site until a delivery succeeds, so watch for failed deliveries.

Is the signing secret the same as my API key?

No. The secret API key lets your server call Stripe. The webhook signing secret, starting whsec_, only verifies that incoming requests came from Stripe, and each endpoint has its own. Keep both on the server, never in browser code, and rotate them if they are ever exposed.

Do I need a webhook if I use Stripe Payment Links?

Only if your site needs to react to payments, such as marking orders paid or granting access. Payment Links work without any code, and Stripe emails receipts, but your site will not know someone paid unless it receives the event or you check the dashboard by hand.

Make one with websites

The button opens the generator with this use case already described. Change the wording to match your own.

Create a website with OneCraft

Related questions

Sources

Written and checked by the OneCraft team. Last checked .