- Signed with HMAC-SHA256 over
"<unix_ts>.<rawBody>", headerX-Cleff-Signature: t=<ts>,v1=<hex>. - Idempotent: every retry of a logical delivery carries the same
id. - Per-Payout ordered by
(occurred_at, sequence); see Ordering and dedup.
(business, environment). A Business has one sandbox endpoint and one
production endpoint. (Fan-out to multiple endpoints per environment is on the roadmap;
the API contract is shaped to add it non-breaking.)
Endpoints
The environment (
sandbox or production) comes from the credential; there is no
path-level selector.
Signing secret
The signing secret is generated by Cleff (formatwhsec_<env>_<random>) and returned
exactly once on POST. Cleff stores it encrypted at rest but cannot reveal it back
to you after creation; if you lose it, POST again to rotate.
POST is idempotent on (business, environment). Posting again rotates the secret
(hard swap: old secret stops verifying immediately; a Stripe-style overlap window is
on the roadmap).
Verifying a delivery
- the header is missing, malformed, or the timestamp is outside a ±300s replay window;
- the recomputed HMAC does not equal the provided
v1hex (use a constant-time compare); - the body has been parsed by middleware that mutated bytes; verify against the raw request body.
Payload envelope
Flat envelope; the event payload lives underdata. The envelope shape is stable;
data is versioned independently via api_version.
Ordering and dedup
Strict wire ordering over a retrying HTTP queue is not achievable, and head-of-line blocking would let one stuck delivery freeze every later event for the same Payout. So the contract is:Receivers order same-Payout events by(occurred_at, sequence)and dedup onid.
occurred_atis the domain-time epoch, stamped when the state changed, not when Cleff happened to enqueue the delivery. Stable across retries.sequenceonly breaks ties when two transitions stamp the sameoccurred_at.idis the idempotency key; storing the highest-(occurred_at, sequence)you’ve applied per Payout makes the integration safe against duplicate delivery and out-of-order arrival.
Retry and dead-lettering
Failed deliveries retry with exponential backoff, up to 8 attempts, stretching the total window to several hours. Anything 2xx counts as delivered; anything else (including network failure) retries. After the budget is exhausted, the delivery lands on Cleff’s internal dead-letter surface and is investigated by Ops; the subscription is not auto-disabled in v1.Event types (v1)
All v1 events carry a shared core projection plus an event-specific tail:rail_ref is the provider’s opaque reference for the disbursement and is null until
the provider returns one, typically populated by payout.disbursed, sometimes earlier.
Cleff’s relationship with the upstream provider is internal: subscribers never see the
provider name, the provider’s payout ID, or the provider’s raw lifecycle strings.
Lifecycle position is conveyed by type.