Skip to main content
Zest delivers lifecycle events to a single partner-registered HTTPS endpoint. Every event uses the same envelope so a single handler can dispatch on eventType.

Universal envelope

Event types

Delivery semantics

  • At-least-once. Zest may deliver the same event more than once. Always dedup on eventId.
  • No ordering guarantees. Two events for the same subject can arrive out of order. Use the occurredAt timestamp as the source of truth for sequencing.
  • Outbox pattern. Events are persisted in Zest’s database before delivery, so a transient delivery failure never loses an event.
  • Retries. See Retries & dead-letter.

Ordering disclaimer

If you process state transitions that depend on order — for example, subscription.completed MUST follow funding_receipt.uploaded — derive ordering from occurredAt, not arrival order. A naive consumer that overwrites state on every receipt may regress when a delayed earlier event arrives second.

Dedup

Persist eventId in your store with at least a 24-hour TTL and reject duplicates. A 24-hour window safely covers the full retry tail (~14h45m) plus margin.

What gets delivered

  • HTTP POST to your registered URL.
  • Content-Type: application/json.
  • Body is the envelope above (UTF-8 JSON).
  • Headers:
    • Zest-Signature: t=<unix>,v1=<hex> — see Verification.
    • Zest-Event-Id: <eventId> — convenience copy.
    • Zest-Event-Type: <eventType> — convenience copy.
    • User-Agent: ZestWebhooks/1.0.

Acknowledging receipt

Return any 2xx response within 10 seconds. Zest treats 4xx and 5xx as failures and triggers the retry schedule. We recommend returning 200 quickly and processing the event asynchronously on your side — long-running processing inside the request hot path will exhaust the 10s budget and cause spurious retries.