Skip to content

Stripe

Ricochet checks Stripe’s Stripe-Signature header the way Stripe’s own libraries do, and can drop Stripe’s retries of an event it already stored.

  1. In the dashboard, create a source and pick Stripe as the sender (verification method stripe). Copy its URL, https://in.getricochet.dev/src_….
  2. In Stripe, open Developers → Webhooks, add an endpoint with that URL and choose the events to send.
  3. Reveal the endpoint’s signing secret (whsec_…) and paste it into the source’s secret.

Stripe’s test mode and live mode endpoints have different secrets. Use a source in your dev environment for test mode and one in production for live mode.

  • Stripe-Signature must carry a timestamp (t=) and at least one v1= signature, an HMAC-SHA256 of <t>.<body> with the secret. Any v1 that matches passes, so Stripe’s own secret rotation keeps working.
  • The timestamp must be within 5 minutes of Ricochet’s clock (tolerance_seconds changes it).

A request that fails is answered 401 and not stored, unless the source quarantines failures. The event in the dashboard shows why it failed (a wrong secret, clock skew, a modified body), and the signature debugger lets you test another secret.

Stripe retries an event until your endpoint answers 2xx, and it can send the same event twice. With the source’s deduplication set to Stripe, a request whose body id (evt_…) was already stored in the last 3 days (the window is configurable) is answered without storing or delivering it again.

The event type is Stripe’s type field, such as invoice.paid. Filter on it in a connection (event_type equals invoice.paid) or in the CLI:

Terminal window
ricochet listen --forward localhost:3000/webhooks --event-type invoice.paid

Send a signed sample to the source without waiting for Stripe:

Terminal window
ricochet trigger stripe invoice.paid
ricochet trigger stripe payment_intent.succeeded --set data.object.amount=500

Samples: charge.refunded, checkout.session.completed, customer.subscription.created, invoice.paid and payment_intent.succeeded.

Your server receives the event as Stripe sent it, Stripe-Signature included, plus Ricochet’s own signature. Verify Ricochet’s signature (one secret per destination, whatever the provider) or keep checking Stripe-Signature with Stripe’s library: the body is delivered byte for byte, unless the connection transforms it. A replay is days later than Stripe’s timestamp, so Stripe’s check fails on old replays; Ricochet’s signature is new on every attempt.