Stripe
Overview
Stripe is the most common provider Splithook is used with. Stripe's HMAC-SHA256 signing scheme includes a timestamp, which means replays break signature verification unless the timestamp is refreshed — exactly what Splithook's re-signing handles.
Configure the webhook in Stripe
- Open the Stripe Dashboard → Developers → Webhooks.
- Click Add endpoint.
- Paste your Splithook endpoint URL:
https://splithook.com/e/{slug}. - Select the events you want to receive (or "Receive all events").
- Click Add endpoint.
Stripe immediately starts sending events to Splithook.
Add the signing secret
- In the Stripe Dashboard → Webhooks → your endpoint → Reveal (Signing secret).
- Copy the value (starts with
whsec_). - In Splithook → Settings → Signing secrets → New.
- Provider: Stripe. Paste the secret. Save.
- In your destination settings, set Signing mode to Re-sign and select this secret.
Your staging handler should have its own whsec_ secret — different from the one Stripe uses. This is the secret you upload to Splithook for re-signing.
Verify signatures in your handler
Use the official Stripe SDK — it handles the timestamp tolerance and signature comparison:
// Node.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// handle event...
res.json({ received: true });
});
# Python
import stripe
event = stripe.Webhook.construct_event(payload, sig_header, os.environ['STRIPE_WEBHOOK_SECRET'])
// PHP
$event = \Stripe\Webhook::constructEvent($payload, $sigHeader, $_ENV['STRIPE_WEBHOOK_SECRET']);
How Splithook re-signs Stripe events
The stripe-signature header format:
stripe-signature: t=1714900000,v1=abc123...,v0=legacy...
On replay, Splithook:
- Replaces
twithMath.floor(Date.now() / 1000). - Recomputes
HMAC-SHA256(secret, "{new_t}.{body}"). - Sends
stripe-signature: t={new_t},v1={new_v1}(drops legacyv0).
Your handler's 5-minute tolerance window resets. The payload is unchanged.
Filtering by event type
Stripe sends the event type in body.type. Use it in your destination filter:
body.type == 'charge.failed'
body.type matches '^payment_intent\.'
body.type in ['invoice.paid', 'invoice.payment_failed']
For live-mode-only forwarding:
body.livemode == true
Testing with Stripe CLI
The Stripe CLI can forward test events directly to your Splithook endpoint:
stripe trigger charge.failed --stripe-account=acct_xxx \
--override charge:capture_method=manual \
| curl -X POST https://splithook.com/e/{slug} \
-H "Content-Type: application/json" \
-d @-
Or use the Stripe Dashboard → Webhooks → Send test webhook.