Skip to content
PostMTA Hosted
StatusSign inOpen panelRequest access
Open menu

Docs

Open in panel → /app · deliveries

Delivery webhooks

Kumo delivery events land at POST /v1/webhooks/kumo/delivery. The endpoint is HMAC-verified and idempotent by event id. The panel lists the last 50 rows via GET /v1/panel/deliveries.

Contract

POST /v1/webhooks/kumo/delivery
X-Postmta-Signature: t=1700000000,v1=<hex(hmac-sha256(secret, t + '.' + body))>
X-Postmta-Event-Id: <dedupe key>
Content-Type: application/json

{
  "workspace_id": "00000000-0000-4000-8000-000000000001",
  "event": "bounce" | "deferred" | "complaint" | "delivered",
  "address": "user@example.com",
  "reason": "mailbox full",
  "ts": "2026-07-12T00:00:00Z"
}

The t (timestamp) must be within ±300 s of server time. The signature covers t + '.' + raw-body (HMAC SHA-256 hex).

Wiring

infra/kumomta-local/policy/hooks_delivery.lua is loaded by init.lua when present. apps/api/src/policyRender.ts writes managed/webhook_config.lua with URL/secret placeholders from env:

WEBHOOK_DELIVERY_URL=http://127.0.0.1:4000/v1/webhooks/kumo/delivery
WEBHOOK_DELIVERY_SECRET=<shared secret>

Optional fan-out targets live in webhook_endpoints (per-workspace URL

Live appliance path

renderWorkspacePolicy writes the active workspace, shared secret, and http://127.0.0.1:4000/v1/webhooks/kumo/delivery into managed/webhook_config.lua. The local Kumo installer copies hooks_delivery.lua beside init.lua, where it is loaded when present. After rendering, bump Kumo’s config epoch so managed policy readers refresh.

Run bash scripts/kumo-delivery-smoke.sh with Kumo on :8000 and local Supabase running; the script starts a temporary API on :4000 when needed. The probe signs a delivery with the API’s signDelivery helper, posts it to the live endpoint, verifies the webhook_deliveries row in Postgres, and prints its row id. Battle-test step 22 runs this probe only when Kumo liveness and the Supabase REST API are available.

Idempotency

X-Postmta-Event-Id is the unique key on webhook_deliveries (unique (workspace_id, event_id)). Retries return { ok: true, idempotent: true } without failing the caller.

Side-effects

event action
bounce / complaint insert into suppressions with reason=event, source='webhook'
deferred / delivered delivery row only
any append row in webhook_deliveries

Tests

Last verified: Sun Jul 12 2026 17:00:00 GMT-0700 (Pacific Daylight Time). Cross-link maintained byscripts/check-docs-drift.sh (M54).

← All docs