Skip to main content
Suby.fi sends signed HTTP POST webhooks to the endpoints you register via POST /v3/webhook-endpoints. Each endpoint has its own signing secret (whsec_…), shown once at creation and on rotation.

Managing endpoints

  • CreatePOST /v3/webhook-endpoints (returns the whsec_… secret once).
  • Subscribe to specific events — set enabledEvents. An empty array subscribes to all events.
  • Rotate the secretPOST /v3/webhook-endpoints/:id/rotate-secret.
  • DisablePATCH with isActive: false.

Event types

Events are named resource.action.

Payment events

Subscription events

Suby drives renewals — you never call the API for cycle N+1:
  • Card / Apple Pay / Google Pay — re-charged off-session on a progressive smart-retry back-off (up to 8 attempts over 30 days). Soft declines (insufficient funds, network, velocity) are retried; hard declines (stolen/lost card, closed account) end the subscription immediately. The current dunning state is on the Subscription object (renewalAttempt, nextRenewalAttemptAt, lastDeclineCategory).
  • Crypto — renewed via a per-cycle email linking to the product’s checkout; the customer re-deposits and the same subscription rolls forward.

Customer & payment-method events

Payout events

Event payload

Every delivery — for all event types — shares the same top-level envelope. The event kind is on the envelope as type; the resource-specific fields are under data (each data carries its own object discriminator). A payment event:
A subscription event (same envelope — only type and data differ):
Branch on the envelope type (or the X-Webhook-Event header) — never on the data shape alone.

Delivery headers

Every delivery carries:

Verifying signatures

The signature is an HMAC-SHA256 of `${timestamp}.${rawBody}` keyed with your endpoint secret. Use the raw request body bytes — do not re-serialize the parsed JSON.
Capture the raw body before any JSON middleware parses it (in Express, use express.raw() on the webhook route, or verify to stash req.rawBody). Reject any delivery whose timestamp is more than 5 minutes old.

Responding

Return a 2xx quickly (ideally < 5s). Non-2xx responses are retried with backoff. Make your handler idempotent — the same event may be delivered more than once.