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 TypeDescription
payment_intent.succeededA payment intent has been successfully confirmed and charged
checkout_session.paidA checkout session has been paid
setup_intent.succeededA setup intent has been confirmed and a payment method saved
invoice.paidAn invoice has been paid
account.updatedAn account's details or capabilities have changed
account.external_bank_account.createdAn external bank account has been added to an account
refund.updatedA 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 TypePayload Field
payment_intent.succeededpayment_intent
checkout_session.paidcheckout_session
setup_intent.succeededsetup_intent
invoice.paidinvoice
account.updatedaccount
account.external_bank_account.createdexternal_bank_account
refund.updatedrefund

Configuring webhooks

Webhook endpoints are managed in the Dashboard under Settings > Developer. To set up a webhook:

  1. Go to Settings > Developer in the Dashboard
  2. Under Webhook Endpoints, click Create
  3. Enter a name, your HTTPS endpoint URL, and select the event types to subscribe to
  4. 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:

FieldDescription
display_nameA human-readable label for the destination
event_typesThe event types to subscribe to
webhook_endpoint.urlThe HTTPS URL to receive events
webhook_endpoint.signing_secretSecret used to verify signatures (generated automatically, prefixed with whsec_)
stateACTIVE 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 generated
  • v1 — the HMAC-SHA256 signature

Verification steps

  1. Extract the t and v1 values from the header
  2. Construct the signed payload: {t}.{request_body} (the timestamp, a dot, then the raw request body)
  3. Compute the HMAC-SHA256 of the signed payload using your signing secret
  4. Compare the hex-encoded result to the v1 value 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:

AttemptDelay
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.