Stripe
Trigger workflows on Stripe payment, subscription, and invoice events.
The Stripe trigger receives any of Stripe's 200+ event types — payment intents, subscription lifecycle, invoice paid/failed, customer events — and starts a workflow with the affected Stripe object available downstream.
How to configure
- In your Stripe Dashboard open Developers → Webhooks → Add endpoint. Paste the Webhook URL as the endpoint URL. Test-mode keys deliver test-mode events; live-mode requires a separate endpoint.
- Pick the Events to send you care about (e.g.
payment_intent.succeeded,customer.subscription.created,invoice.paid) — orReceive all eventsfor general routing. After clicking Add endpoint, Stripe shows the endpoint's Signing secret (whsec_...). Copy it and paste into the trigger's signing-secret field — without it the trigger default-denies with401. - Stripe signs requests as
Stripe-Signature: t=<ts>,v1=<hex>wherev1is HMAC-SHA256 of<ts>.<raw_body>using thewhsec. The platform enforces a 5-minute timestamp tolerance to prevent replays. Read<stripe1.type>for the event name and<stripe1.data>for the affected object — e.g.<stripe1.data.object.amount>on apayment_intent.succeeded. - Verify with Stripe's built-in tester — open the endpoint, click Send test webhook, choose
payment_intent.succeeded, and confirm a200in the delivery log. Stripe retries failed deliveries with exponential backoff for up to 3 days; the trigger ACKs200immediately and fans out asynchronously.
Signature format
| Header | Value |
|---|---|
Stripe-Signature | t=<unix-seconds>,v1=<hex> — v1 is HMAC-SHA256 of <t>.<raw_body> with the whsec_... secret |
Replay window: 5 minutes from t. The Stripe event.id (e.g. evt_3OabCDe…) is used as the webhook_event_dedup key, so Stripe's automatic retry behaviour produces zero duplicate workflow runs.
Sample payload (payment_intent.succeeded)
{
"id": "evt_3OabCDeFgHiJkLmN1234",
"object": "event",
"api_version": "2025-09-30.clover",
"created": 1745700000,
"type": "payment_intent.succeeded",
"livemode": false,
"pending_webhooks": 1,
"request": {
"id": "req_aBcDeFgHiJkLmNo",
"idempotency_key": "idem_2026-04-26_pi_12345"
},
"data": {
"object": {
"id": "pi_3OabCDeFgHiJkLmN5678",
"object": "payment_intent",
"amount": 4999,
"amount_capturable": 0,
"amount_received": 4999,
"currency": "usd",
"customer": "cus_QXyzABCDEFG",
"description": "Pro plan — monthly",
"metadata": { "workspaceId": "ws_42", "planId": "pro_monthly" },
"payment_method": "pm_1OabCDeFgHiJkLmN",
"payment_method_types": ["card"],
"receipt_email": "alex@example.com",
"status": "succeeded",
"latest_charge": "ch_3OabCDeFgHiJkLmN1234",
"created": 1745699998
}
}
}Verify with the bundled scripts
bun apps/sat/tests/staging/triggers/stripe/verify.ts \
https://mybotbox.com/api/webhooks/trigger/<path> \
--secret=whsec_<your-test-secret>python3 apps/sat/tests/staging/triggers/stripe/verify.py \
https://mybotbox.com/api/webhooks/trigger/<path> \
--secret=whsec_<your-test-secret>Source: apps/sat/tests/staging/triggers/stripe/.
Troubleshooting
401on every event — wrongwhsec_...pasted in the trigger. Each endpoint has its own signing secret — copy the one for the endpoint Stripe is calling. Live-mode and test-mode endpoints have separate secrets.401timestamp out of tolerance — caller clock drift, or you replayed a captured event much later. The platform enforces a 5-minute window; re-fire from the Stripe dashboard's tester to mint a fresht.- Workflow doesn't fire on a real charge — check the Events filter on the endpoint.
Send all eventsis broad but expensive; the more commonSend specific eventswon't fire for event types you didn't tick. - Duplicate runs — extremely unlikely; Stripe rarely re-delivers the same
evt_...andwebhook_event_dedupwould catch it. If you see them, confirm migration 0109 has been applied and check the delivery log for distinct event IDs.