How requests are processed
Every request that reaches an endpoint walks the same fixed pipeline, in the same order — and it is acknowledged and durably buffered before any of your configuration runs. Verification, routing, transforms and delivery all happen after the event is safe on disk, so a misconfigured endpoint can never lose a webhook. This page walks the pipeline stage by stage; the console's endpoint Overview shows the same stages live for your latest request.
The pipeline
sender ──▶ ① ack & buffer ──▶ ② respond ──▶ ③ verify ──▶ ④ store ──▶ ⑤ route ──▶ ⑥ deliver
(edge) (edge) (processing plane ──────────────────────▶)
│
└──▶ ⚲ mirror (additive, pre-verification)| # | Stage | Where | What happens |
|---|---|---|---|
| ① | Ack & buffer | edge | The request is accepted and durably buffered, and a time-sortable event id (ULID) is minted — this id follows the event through every later stage and log. |
| ② | Respond | edge | The sender gets its synchronous answer immediately: the default 200 · {"received":true}, a provider handshake (Slack url_verification, Meta hub.challenge, …), or your custom response rules / response proxy. The sender is never kept waiting on your downstream. |
| ③ | Verify | processing plane | If the endpoint has signature verification configured, the signature is checked here — after the ack, per the verify-as-verdict model. A passing event continues; a failing signature is quarantined — durable and inspectable, never delivered, never a 401, never silently dropped. |
| ④ | Store | processing plane | The event and the raw request (headers + body) are written to the log — replayable for the retention window (30 days by default). Bodies over the claim-check threshold are spilled to object storage and resolved transparently on read. |
| ⑤ | Route | processing plane | The endpoint's routes fan the event out to its destinations, applying any per-route filters and transforms. No destinations configured means the pipeline stops here by design — the event is stored and pullable. No matching route parks the event as unrouted, replayable once a route exists. |
| ⑥ | Deliver | processing plane | Each destination gets the request envelope — { url, method, headers, data, received_at } (or your transform's output with the original under original) — with Standard-Webhooks signing, a 15 s timeout, jittered retries (8 attempts over ~28 h), a per-destination circuit breaker, and a dead-letter queue on exhaustion. Every attempt is logged. |
The guarantee that falls out of the ordering: configuration can never drop a webhook. Stages ③–⑥ only ever decide what happens to an event that already exists durably.
Mirror: an additive parallel tee
If the endpoint has a mirror attached, a byte-exact copy of the request is teed to the mirror URL in parallel — branching off after the event is buffered (stage ①) and before verification (stage ③), so a signature-failed (quarantined) request still mirrors, and the downstream verifies the provider's original signature itself. Mirroring is purely additive: it uses the same delivery machinery (15 s timeout, jittered retries, per-destination circuit breaker, DLQ, every attempt logged) but never affects the sender's response, the verdict, routing, or delivery. A held (paused-endpoint) request mirrors on unpause/replay; a dropped_unknown request never mirrors. In the console trace the mirror shows as a Mirrored stage on your latest request when an attempt exists.
Every outcome, named
A request always ends in exactly one outcome, and the event it creates can then reach one of a few downstream states. The console label and the underlying pipeline name line up:
| Pipeline outcome / state | Console shows | Meaning | Recoverable? |
|---|---|---|---|
accepted | stored | Received, responded, stored. Routed and delivered if routes exist. | — (this is success) |
parked_inactive | held | The endpoint exists but is paused — the event is stored, nothing is delivered. | Yes — resumes on unpause, or replay |
dropped_unknown | rejected | No endpoint matched the path. Counted and inspectable in the request log; no event is created. | Replay after creating the endpoint |
event quarantined | quarantined | Signature verification failed. Stored, inspectable, never delivered. | Yes — inspect, fix the secret, replay |
event unrouted | unrouted | Endpoint active but no route matched. | Yes — add a route, replay |
event dlq | dead-letter | Delivery exhausted all retries. | Yes — redrive |
See it happen
Send a request to your endpoint, then read back exactly what the pipeline did with it:
# 1) A provider (or you) POSTs to your endpoint
curl -s https://<ingest-domain>/<your-slug> \
-H "Content-Type: application/json" -d '{"hello":"world"}'
# → 200 {"received":true} (stage ② — answered at the edge)
# 2) The raw request, as the front door saw it (stage ④)
curl -s "https://api.emithook.com/v1/requests?endpoint=<endpoint-id>" \
-H "Authorization: Bearer $EMITHOOK_API_KEY"
# 3) The event with every delivery attempt (stages ⑤–⑥)
curl -s "https://api.emithook.com/v1/events/<event-id>" \
-H "Authorization: Bearer $EMITHOOK_API_KEY"In the console, the endpoint's Overview renders this as the Your latest request trace — one row per stage that actually ran, with per-stage timestamps.
Where to go next
- Requests & replay — inspect the request log and re-run anything.
- Responses & transformations — customize stage ② and stage ⑤.
- Security — verification schemes, quarantine, and outbound signing.