Skip to main content
Plinth pushes signed, retried events to your endpoints so you never have to poll. Every state change (activation, renewal, dunning, cancellation, invoice paid…) is written to a transactional outbox and delivered to each of your registered endpoints.
1

Register an endpoint

The response includes a secret (whsec_…) shown only once — store it. It signs every delivery to this endpoint. You can also add endpoints and rotate secrets from the dashboard (Webhooks). Pass event_types to subscribe to a subset; omit it to receive everything.
2

Verify the signature and handle the event

Each request carries a Plinth-Signature: t=<unix>,v1=<hmac> header. The signature is HMAC-SHA256("<t>.<raw body>") keyed by your endpoint secret. Verify against the raw body, before parsing JSON.
Next.js — app/api/plinth/webhook/route.ts
Return a 2xx quickly to acknowledge. Any non-2xx (or a timeout) is retried.

The event envelope

Every delivery has the same shape. Your handler switches on type and reads data.object.
See the event catalog for every type and its data.object.

Delivery, retries & idempotency

  • Retries. A failed delivery (non-2xx or timeout) is retried with exponential backoff — up to 8 attempts — then marked failed. Watch every attempt under Webhooks → deliveries, and Resend any delivery manually.
  • Idempotency. Deliveries can arrive more than once. Treat event.id as an idempotency key — ignore an id you’ve already processed.
  • Ordering. Events are delivered roughly in order but not guaranteed; rely on the resource’s current state (or created) rather than assuming strict order.
  • Security. Always verify the signature. Reject anything that doesn’t match your endpoint secret.