Skip to content

Set up the Stripe webhook

PurchasesMay 27, 2026·14 min read·Updated June 4, 2026

The Stripe webhook is required for Stripe payments to work with Off The Couch. Without it, the customer's card is charged in Stripe, but Off The Couch never finds out, the cart times out, and the customer sees:

Invalid transaction! Your cart has expired

If your booking site uses Stripe and customers are hitting that error after entering valid cards, the webhook is the first thing to check.

This article walks through the full setup in the Stripe Dashboard. Stripe's own reference is at docs.stripe.com/webhooks; this guide is the Off The Couch-specific version with the OTC URL, the right event selection, and the round-trip of pasting the signing secret back into OTC.

Why the webhook exists

Stripe processes the card asynchronously. Off The Couch needs to know the moment the charge succeeds (or fails, or is disputed) so it can mark the booking paid, send the confirmation email, and free the cart. The webhook is how Stripe tells Off The Couch. See Stripe: Receive webhook events for the underlying mechanism.

If the webhook isn't set up, every Stripe payment looks like a timeout to Off The Couch, even though the customer was charged in Stripe.

What you'll need

ItemWhere to get it
A Stripe accountstripe.com
Your Stripe API keys connected to OTCPayment gateways (already configured if you've connected Stripe before)
Access to the Stripe Dashboarddashboard.stripe.com

You'll add two webhook destinations: one for test mode (for booking-site testing without real cards) and one for live mode (for real customer payments). The two are independent. If you only set up one, the other mode fails.

A note on Stripe's UI terminology

Stripe recently renamed "webhook endpoints" to event destinations as part of moving the developer tools into a new section called Workbench (which replaces the older "Developers Dashboard"). Both terms still appear in Stripe's docs; for our purposes, "destination" and "endpoint" mean the same thing. Stripe's reference: Trigger reactions in your integration with Stripe events.

Step-by-step

1. Copy the webhook URL from Off The Couch

StepAction
1Go to Purchases > Payment settings
2Switch to the Payment gateways tab
3Confirm Stripe is the active gateway. If it isn't, set it up first (Payment gateways)
4Scroll to the Webhook section (badge: important)
5Click the copy icon next to the URL: https://api.offthecouch.io/stripe-webhook

This URL is the same for every Off The Couch venue. Don't be alarmed; OTC routes incoming Stripe events to the right group based on the Stripe account that sent them.

2. Open the Stripe Workbench webhooks tab

StepAction
1Open dashboard.stripe.com and sign in
2Top-right toggle: pick Test mode or Live mode. Start with Test mode for the first run-through
3Open Workbench (newer accounts) or Developers > Webhooks (legacy). Direct link in either: dashboard.stripe.com/webhooks
4Click the Webhooks tab in Workbench
5If you have older endpoints from prior setup attempts, you'll see them listed. If not, you'll see an empty state with the Add destination button

Test mode and Live mode are completely separate worlds in Stripe. Webhooks added in Test mode only fire on test charges; webhooks added in Live mode only fire on real charges. You'll repeat this flow twice (once per mode). Stripe's note: Test and live mode.

3. Open the Create an event destination modal

StepAction
1Click + Add destination within the Webhooks tab.
2A modal titled Create an event destination opens. The left side shows a three-step stepper: Select eventsChoose destination typeConfigure your destination. You'll move through these in order

If your dashboard still uses the older "Developers Dashboard" UI, the button is labeled + Add endpoint and there's no destination-type step (the only option was always a webhook endpoint). The rest of the flow is the same. Stripe reference: Add a webhook endpoint.

4. Step 1 of 3 — Select events

The right pane header reads Configure your event destination.

StepAction
1Under Event destination scope, leave Your account selected (the default). This is the right choice unless you're using Stripe Connect with separate sub-accounts
2Leave API version at its default unless Stripe instructs otherwise
3Below Events, two tabs appear: All events and Selected events. Stay on All events
4In the Find event by name or description... search box, type payment_intent
5The list filters down to the Payment Intent group with 8 events. Click the arrow to expand it
6Click the Select all Payment Intent events checkbox at the top of the group. All 8 events get checked
7(Optional) Switch to the Selected events tab to confirm exactly 8 events are selected, all prefixed with payment_intent.
8Click Continue at the bottom right

You don't need any other event types. If you select more, OTC ignores them; if you select fewer than the full payment_intent.* set, some failure / cancellation paths won't propagate back to Off The Couch.

Stripe's full event catalog: Stripe API: Event types.

5. Step 2 of 3 — Choose destination type

The right pane header reads Choose where you want to send events.

StepAction
1Three destination-type tiles appear: Webhook endpoint ("Send webhook events to a hosted endpoint"), Amazon EventBridge ("Send events to your AWS account"), and Azure Event Grid ("Send events to your Azure account")
2Click Webhook endpoint (the other types aren't used by OTC)
3Click Continue at the bottom right

6. Step 3 of 3 — Configure your destination

The right pane header reads Configure destination with the subtitle "Tell Stripe where to send events and give your destination a helpful description." A summary block shows: Events from = Your account, Payload style = Snapshot, the chosen API version, and Listening to = 8 events.

StepAction
1Destination name — type a short name like Off The Couch Platform
2Endpoint URL — paste https://api.offthecouch.io/stripe-webhook (Stripe shows the helper text "Webhooks require a URL to send events to")
3Description (optional but recommended) — type something like Off The Couch Platform integration so you can identify this destination later
4Click Create destination at the bottom right
5Stripe creates the destination and lands you on its detail page

7. Copy the signing secret (recommended)

The signing secret is how Off The Couch confirms each incoming webhook is genuinely from Stripe and not a spoofed call. It's optional in the sense that OTC will accept unsigned webhooks, but strongly recommended for production: without it, anyone who learns your endpoint URL could submit fake webhook events. Stripe reference: Check the webhook signatures.

StepAction
1On the destination's detail page, find the Signing secret section
2Click Click to reveal to show the secret
3Copy the secret. It starts with whsec_ and is followed by a long random string

8. Paste the signing secret into Off The Couch

StepAction
1Back in Payment settings > Payment gateways, scroll to the Webhook Secret section
2Click Add webhook secret (the page shows "No webhook secret configured" with a warning icon if none is set yet)
3Paste the whsec_... value into the Webhook endpoint secret field
4Click Save
5The page now shows Webhook signature verification enabled with a green checkmark

9. Repeat for the other mode

If you started in Test mode, repeat steps 2-8 in Live mode (or vice versa). The signing secret is different for each mode; paste the right one into OTC for the mode you're currently using.

Important: If you switch the OTC payment gateway between test and live mode (using the live/test toggle on the Payment gateways tab), make sure the corresponding signing secret is in Webhook Secret. Otherwise signature verification fails and the webhook is rejected.

10. Verify with a test booking

StepAction
1Switch your Stripe credentials in OTC to test mode (toggle on the Payment gateways tab)
2On your booking site, start a new booking
3At checkout, use a Stripe test card like 4242 4242 4242 4242 with any future expiration and any 3-digit CVC
4Complete the booking. You should see the success screen, not "Invalid transaction! Your cart has expired"
5In the Stripe Workbench, go back to your destination's detail page and check the Events tab. You should see payment_intent.succeeded and payment_intent.created with 2xx response codes

If you see 4xx or 5xx responses, the webhook fired but Off The Couch couldn't process it. Check the Webhook signature verification state on OTC (most common cause: the signing secret is wrong or for the other mode).

Stripe's debugging reference: Webhook event delivery and retries.

11. Switch to Live mode for real payments

Once the test-mode flow works end-to-end:

StepAction
1Confirm your Live-mode webhook destination is added in the Stripe Dashboard (separate from Test mode)
2Confirm the Live mode signing secret is pasted into OTC's Webhook Secret field
3Switch your OTC payment gateway to Live mode on the Payment gateways tab
4Take a small real payment (your own card) as a final verification

Reference

OTC webhook URL

https://api.offthecouch.io/stripe-webhook

Same URL for every venue, every mode. Stripe sends the events to OTC; OTC identifies your venue from the Stripe account ID on the event.

Required Stripe events

All events in the payment_intent group:

  • payment_intent.created
  • payment_intent.succeeded
  • payment_intent.payment_failed
  • payment_intent.canceled
  • payment_intent.processing
  • payment_intent.requires_action
  • payment_intent.amount_capturable_updated
  • payment_intent.partially_funded

Off The Couch only acts on a subset, but the easiest setup is "all payment_intent.* events." Stripe's catalog can change; the bulk-select pattern is future-proof. Full Stripe catalog: Stripe API: Event types.

Signing secret format

whsec_ followed by ~30-40 alphanumeric characters. Found in the Stripe Workbench under the destination's detail page, Signing secret card, Click to reveal.

OTC Webhook Secret states

StateWhat you see in OTC
Not configuredWarning icon + "No webhook secret configured" + Add webhook secret button
ConfiguredMasked secret + Webhook signature verification enabled (green) + Edit / Remove buttons
EditingPassword input + helper text "Leave empty to disable signature verification (not recommended for production)" + Cancel / Save

Stripe UI naming (current vs legacy)

ConceptCurrent (Workbench)Legacy (Developers Dashboard)
Where to find itWorkbench > Webhooks tabDevelopers > Webhooks
Add button+ Add destination+ Add endpoint
What you're creatingEvent destination (then pick Webhook endpoint type)Webhook endpoint
Secret labelSigning secret > Click to revealSigning secret > Reveal

Both flows produce a working webhook. Direct link to either: dashboard.stripe.com/webhooks.

Test mode vs Live mode

AspectTest modeLive mode
Stripe Dashboard toggleTop rightTop right
Webhook destinationSeparate destination in Test mode dashboardSeparate destination in Live mode dashboard
Signing secretDifferent whsec_... valueDifferent whsec_... value
OTC gateway toggleTest on Payment gateways tabLive on Payment gateways tab
Cards acceptedTest cards only (4242 4242 4242 4242)Real cards only

Stripe documentation references

Good to know

  • Webhook is required, not optional. The "important" badge in OTC is understating it. Without the webhook, Stripe payments will show "Invalid transaction! Your cart has expired" to the customer even though the card was charged. Setting the webhook up is part of going live with Stripe, not a nice-to-have.
  • Test and live each need their own destination. Stripe treats Test and Live as separate accounts for webhook purposes (Stripe: Test and live mode). Doing it for one mode and not the other means the unconfigured mode fails.
  • The signing secret is mode-specific. Test mode's secret is different from Live mode's secret. If you switch OTC between modes, swap the secret too.
  • Stripe charges the customer even when the webhook is missing. This is the part that catches venues out: the customer sees "Invalid transaction!" and assumes the payment didn't go through, but in Stripe it did. Refund the orphan charge from the Stripe Dashboard if a customer reports double-paying.
  • The endpoint URL is shared across all venues. OTC routes incoming events to the right venue using the Stripe account ID on each event. Don't be alarmed that the URL doesn't include your venue name.
  • Pick Webhook endpoint for destination type. The new Workbench flow asks what kind of destination you want (Webhook endpoint, Amazon EventBridge, Azure Event Grid, local listener). OTC only handles Webhook endpoint. The other types are for direct integrations with cloud providers and aren't relevant to OTC.
  • You only need payment_intent.* events. Other event groups (charge, invoice, customer, etc.) aren't used by Off The Couch. Adding them doesn't break anything, but the bulk-select on payment_intent is sufficient.
  • Disabled signing means anyone can fake events. If signing verification is off, the destination accepts events from any source that knows the URL. The URL isn't a secret, so production sites should always have a signing secret. See Stripe: webhook signature verification.
  • Old endpoints can stay. If you have prior test destinations from earlier setup attempts, you can either delete them or leave them; OTC accepts events from any matching destination.
  • Stripe retries failed deliveries. If OTC is temporarily down when a webhook fires, Stripe retries with exponential backoff for up to 3 days (Stripe: retries). The customer's booking eventually marks paid when delivery succeeds.

FAQ

Q: A customer paid in Stripe but their booking shows unpaid / shows "Invalid transaction." What do I do?

A: The webhook isn't reaching OTC. Two things to fix:

  1. Set up the webhook following the steps above (most common: it was never set up).
  2. While you're sorting that out, refund the orphan Stripe charge from your Stripe Dashboard so the customer isn't double-paid when they retry.

After the webhook is set up, ask the customer to try again; the new payment will register correctly.

Q: I added the webhook, but customers still see the timeout error.

A: Check the mode. If your OTC gateway is in Live mode but you only added the webhook in Stripe's Test mode dashboard (or vice versa), the modes don't match. Add the webhook in the matching mode and make sure the signing secret in OTC is from that mode's destination.

Q: I don't see "Workbench" in the Stripe Dashboard. What now?

A: Some accounts still use the older Developers Dashboard. In that case, navigate to Developers > Webhooks in the left sidebar, and click + Add endpoint instead of + Add destination. The rest of the flow is the same (URL, events, signing secret). Direct link works in either UI: dashboard.stripe.com/webhooks.

Q: Where in Stripe is the signing secret?

A: After creating the destination, you land on its detail page. Find the Signing secret section and click Click to reveal to show the secret. It starts with whsec_. Stripe's reference: Verify webhook signatures.

Q: What's the difference between a "destination" and a "webhook endpoint"?

A: Stripe's newer Workbench UI uses "destination" as the umbrella term for any place that receives Stripe events (webhook endpoint, Amazon EventBridge, Azure Event Grid, local listener). When you pick Webhook endpoint as the destination type, you're creating exactly the same thing the older UI called an "endpoint." Off The Couch only handles the webhook endpoint type.

Q: Can I use one webhook for multiple Off The Couch venues?

A: Yes, automatically. The webhook URL is the same for every venue, and OTC routes incoming events using the Stripe account ID on each event. If you have multiple groups with different Stripe accounts, each Stripe account needs its own webhook (added in that account's Stripe Dashboard).

Q: My webhook destination shows red exclamation marks or failed deliveries in Stripe.

A: That means recent delivery attempts failed. Click into the destination, open the Events tab, and click a failed event to see Off The Couch's response. Common causes: signing secret mismatch (401 in the response body), or the destination was added in the wrong mode (no matching OTC group).

Q: Should I add other Stripe events besides payment_intent?

A: Not currently. Off The Couch only acts on payment_intent.* events today. Adding others (e.g., charge.refunded) doesn't cause problems, but it also doesn't enable any extra behavior.

Q: Can I skip the signing secret to save time?

A: For test-mode setup, yes (no real money is at risk). For live mode, no. Without the secret, anyone who learns your webhook URL can submit fake payment_intent.succeeded events that mark bookings as paid without any real Stripe charge.

Q: My venue uses Connect / sub-accounts. Anything different?

A: Stripe Connect users should still add the destination to the main account, with Your account selected on the events screen (not Connected accounts). The Off The Couch handler isn't currently wired for Connect-only events.

Q: Where do I see what events have fired?

A: In the Stripe Workbench, open your destination's detail page and click the Events tab. Each row shows the event type, timestamp, and Off The Couch's HTTP response. 2xx is success; 4xx or 5xx indicates a problem on the OTC side. You can also use Stripe's event log search.

Q: I see a 401 response to webhook events.

A: The signing secret pasted in OTC doesn't match the one Stripe is signing with. Re-copy the secret from the Stripe Workbench (making sure you're in the right mode), paste it into the OTC Webhook Secret field, and save.

Q: I see a 5xx response to webhook events.

A: Off The Couch is having trouble processing the event. File a Support ticket with the event ID from the Stripe Workbench (visible on the event row) so we can look it up in our logs.

Q: I deleted my webhook destination by accident. Will Stripe re-create it?

A: No. Add a new one following this guide. Past payments that were already processed are unaffected (Off The Couch already received those events); but any pending payments that haven't completed yet won't reach Off The Couch until you re-create the destination. Stripe holds undelivered events in its retry queue for up to 3 days (Stripe: retries), so if you re-create within that window, in-flight events do eventually arrive.

Q: Is there an automated way to add the destination instead of doing it in the dashboard?

A: Yes, Stripe supports creating destinations via API (Stripe API: Event destinations) and CLI (Stripe CLI). For a single venue, the dashboard flow above is faster. For repeated setup across many test environments, the CLI is worth a look.