Skip to main content

Webhooks

GET|POST /v0/webhooks · GET|PATCH|DELETE /v0/webhooks/:id (inbox and project twins, plus /headers sub-routes).
Secrets are whsec_…. Every delivery carries svix-id, svix-timestamp and svix-signature (v1,<base64 HMAC-SHA256 of "id.timestamp.body">) — verify with the Svix library or verifySignature() in @lupin/sdk with the raw body and all three headers. The SDK rejects timestamps outside a five-minute window; keep the receiver clock synchronized. Multiple space-separated v1 signatures are supported during rotation. Parse JSON only after verification.
This replaces the pre-audit three-argument hex helper: the third argument is now a Headers object or an object containing all three svix-* headers. Event types: email.received (+ .spam / .blocked / .unauthenticated variants), email.sent, email.delivered, email.bounced, email.complained, email.rejected, email.opened, domain.verified. Payloads wrap the resource: { type: "event", event_type, event_id, message: … }. Filter by scope with inbox_ids / project_ids at create time, or add_inbox_ids / remove_inbox_ids (and project equivalents) on update.

Custom headers

Values are write-only: sent with each delivery, never returned. GET …/:id/headers lists names only; PATCH rotates atomically:
At least one set or remove is required; a header can’t appear in both. email.sent means the outbound provider accepted the send. email.delivered is reserved for a recipient delivery receipt; the current outbound adapters do not wire those receipts, so do not assume this event will follow every send.