Webhooks
Webhooks
Webhooks notify your server when events happen in your account. You configure an event destination with a URL, and Synapto sends HTTP POST requests to that URL when subscribed events occur.
Event types
| Event Type | Description |
|---|---|
payment_intent.succeeded | A payment intent has been successfully confirmed and charged |
checkout_session.paid | A checkout session has been paid |
setup_intent.succeeded | A setup intent has been confirmed and a payment method saved |
invoice.paid | An invoice has been paid |
account.updated | An account's details or capabilities have changed |
account.external_bank_account.created | An external bank account has been added to an account |
refund.updated | A refund's status has changed |
Event payload
Events are delivered as JSON with the following structure:
{
"name": "accounts/acct_YOUR_ACCOUNT/events/evt_EVENT_ID",
"type": "payment_intent.succeeded",
"event_time": "2025-11-17T16:49:42Z",
"payment_intent": {
"name": "accounts/acct_YOUR_ACCOUNT/payment-intents/pi_PAYMENT_INTENT_ID",
"amount": "10000",
"currency": "GBP",
"state": "SUCCEEDED"
}
}The payload field varies by event type:
| Event Type | Payload Field |
|---|---|
payment_intent.succeeded | payment_intent |
checkout_session.paid | checkout_session |
setup_intent.succeeded | setup_intent |
invoice.paid | invoice |
account.updated | account |
account.external_bank_account.created | external_bank_account |
refund.updated | refund |
Configuring webhooks
Webhook endpoints are managed in the Dashboard under Settings > Developer. To set up a webhook:
- Go to Settings > Developer in the Dashboard
- Under Webhook Endpoints, click Create
- Enter a name, your HTTPS endpoint URL, and select the event types to subscribe to
- Copy the signing secret — it's only shown once (you can rotate it later)
Webhook endpoints must use HTTPS.
Event destinations
Each event destination has:
| Field | Description |
|---|---|
display_name | A human-readable label for the destination |
event_types | The event types to subscribe to |
webhook_endpoint.url | The HTTPS URL to receive events |
webhook_endpoint.signing_secret | Secret used to verify signatures (generated automatically, prefixed with whsec_) |
state | ACTIVE or SUSPENDED |
Verifying webhook signatures
Every webhook request includes a Synapto-Signature header that you should verify to ensure the request came from Synapto.
Header format
Synapto-Signature: t=1759581623,v1=f0c3e10b74a338ef0fa494da0613853a7ca6062be6c885f797256df31125737b
t— the UNIX timestamp (seconds) when the signature was generatedv1— the HMAC-SHA256 signature
Verification steps
- Extract the
tandv1values from the header - Construct the signed payload:
{t}.{request_body}(the timestamp, a dot, then the raw request body) - Compute the HMAC-SHA256 of the signed payload using your signing secret
- Compare the hex-encoded result to the
v1value using a constant-time comparison to prevent timing attacks
Example (Node.js)
const crypto = require("crypto");
function verifyWebhookSignature(requestBody, signatureHeader, signingSecret) {
const [tPart, v1Part] = signatureHeader.split(",");
const timestamp = tPart.replace("t=", "");
const signature = v1Part.replace("v1=", "");
const payload = `${timestamp}.${requestBody}`;
const expected = crypto
.createHmac("sha256", signingSecret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex")
);
}Delivery details
- Method: POST
- Content-Type:
application/json - User-Agent:
synapto-webhook - Expected response: Return HTTP 200 to acknowledge receipt. Any other status code is treated as a failure.
Retry behavior
Failed deliveries are retried up to 2 times with increasing delays:
| Attempt | Delay |
|---|---|
| 1 | ~30 seconds |
| 2 | ~2 minutes |
A small amount of jitter (up to 60 seconds) is added to each delay.
After all 3 attempts are exhausted, the delivery is marked as failed. Each attempt is recorded with full request/response details.
Parent account events
If the event occurs on a sub-account, the event is delivered to both the sub-account's destinations and the parent account's destinations. This lets platform accounts receive events from all their sub-accounts with a single webhook endpoint.
Updated about 1 month ago