Skip to main content

Overview

SwiftPay posts a signed HTTP POST request to your configured endpoint whenever a payment event occurs. Every delivery includes an HMAC-SHA256 signature so you can verify the request originated from SwiftPay and has not been tampered with.

Dashboard setup

  1. Open the Webhooks page in the SwiftPay dashboard.
  2. Enter an HTTPS URL in the Endpoint URL field and click Save.
  3. A whsec_* signing secret is generated. The full value is always accessible from the Webhooks page in the dashboard.
  4. The endpoint shows Active once saved.
To update the URL later, click the pencil icon next to the URL field, make your change, and save again. To remove the endpoint, click Remove. A confirmation prompt appears before the endpoint is deleted.

Secret rotation

  • On the Webhooks page, click Rotate Secret.
  • A confirmation dialog is shown — confirm to generate a new whsec_* secret.
  • The old secret is invalidated immediately. Copy the new secret and update your server environment as soon as possible — any webhook delivery verified against the old secret will fail.

Request headers

Every webhook delivery includes the following HTTP headers:
HeaderDescription
Content-Typeapplication/json
User-Agentswiftpay-client/v0.1.0
X-SwiftPay-EventIdUUID of this delivery attempt
X-SwiftPay-TimestampUnix timestamp (seconds) when the delivery was sent
X-SwiftPay-SignatureHMAC-SHA256 hex signature (see Signature verification)

Signature verification

Each delivery is signed so you can confirm it came from SwiftPay. Signed message format
{X-SwiftPay-Timestamp}.{raw request body}
Algorithm: HMAC-SHA256, keyed with your whsec_* signing secret Output: lowercase hex string Replay protection: reject deliveries where |now − X-SwiftPay-Timestamp| > 300 seconds (5 minutes).
const crypto = require('crypto');

function verifySignature(secret, timestamp, rawBody, signature) {
  const msg = `${timestamp}.${rawBody}`;
  const expected = crypto.createHmac('sha256', secret).update(msg).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
Always use a constant-time comparison function (timingSafeEqual / hmac.compare_digest) to prevent timing attacks.

Retry behaviour

  • SwiftPay attempts delivery up to 5 times per event.
  • If your endpoint does not return an HTTP 2xx response the delivery is retried on the following backoff schedule:
AttemptDelay before retry
2nd5 seconds
3rd30 seconds
4th2 minutes
5th10 minutes
  • After 5 failed attempts the delivery is marked failed and will not be retried.
  • Delivery history — including attempt count, HTTP status codes, and timestamps — is visible in the dashboard under Webhooks → Delivery log.

Event catalogue

All event payloads share the following envelope fields. Additional fields specific to each event type are documented in the corresponding tab.
FieldTypeDescription
eventstringEvent type identifier (e.g. payment.detected)
invoiceIdstringUUID of the invoice
referencestringSwiftPay-generated short reference for the invoice
externalRefstring | nullYour own reference passed when the invoice was created
statusstringCurrent invoice status (pending, partial, paid, completed)
token.symbolstringToken symbol (e.g. USDC)
token.networkstringNetwork ID the payment was received on (e.g. base)
amountsobjectAmount details — fields vary by event type (see individual tabs)
metadataobjectKey-value pairs you attached to the invoice at creation time