Skip to content

Webhook delivery and recovery

Core payment outcome notifications and managed billing outbox events use durable at-least-once delivery. Your endpoint must tolerate duplicate events and out-of-order arrival. Historical deliveries and other legacy publishers are not automatically converted to durable events.

Delivery behavior

  • Success is a 2xx response followed by a committed outbox acknowledgement.
  • A lost acknowledgement can cause another delivery even after your endpoint returned 2xx.
  • Durable retries have no finite attempt cap or automatic expiry. Backoff starts at two minutes and caps at 1,024 minutes; eligible events are picked up by the delivery worker.
  • Worker claims lease for three minutes; an expired lease can be recovered after a restart.
  • Retries preserve the event ID, signed payload and queued destination. Changes to webhook settings affect new events.
  • No global or per-payment ordering is guaranteed. Read current payment status when reconciling stale or contradictory events.
Durable consumer pattern (pseudocode)
verifySignature(event); // JSON security.signature; exclude security when signing

// Deduplication and business effects must commit atomically.
await database.transaction(async (tx) => {
  if (!(await tx.insertEventIdIfAbsent(event.id))) return;
  await applyIdempotentBusinessEffect(tx, event);
});

return res.status(200).json({ received: true });

Requests use Content-Type: application/json and the Tinker Payments webhook User-Agent. The event ID and HMAC-SHA256 signature are in the JSON body. Delivery-ID, retry-attempt and signature headers are not part of the current contract.

Investigate delivery backlog and recovery