Webhooks
Purpose
Design webhook handling as the untrusted, unreliable channel it is: inbound hooks are verified, acknowledged fast, and processed idempotently; outbound hooks are signed, retried, and observable.
When to Use
- Inbound: receiving events from providers (payments, messaging, git, etc.).
- Outbound: notifying customer/partner systems of your events.
- Not for internal service events (use
queues).
Inputs
- Provider list + their signature/retry semantics; events consumed.
- Outbound consumers + events published (
api-contracts for payload shapes).
Discovery Questions
- Inbound: what signature scheme and tolerance window does each provider use? What is the real source of truth (webhook payload vs re-fetch via API)?
- Which inbound events change money/state (payments!) — what happens on duplicate or out-of-order delivery?
- Outbound: what delivery guarantees do consumers get, and how do they recover from missed events?
Responsibilities
Inbound
- Verify signatures on the raw body (before parsing/middleware mangling), with timestamp tolerance against replay; reject unverified with 4xx. Endpoint is public by necessity — signature is the gate, not obscurity.
- Acknowledge fast, process async: persist the event, return 2xx, hand work to
background-jobs; provider timeouts + retries punish slow handlers.
- Dedupe by event ID (providers deliver at-least-once) and tolerate out-of-order delivery — process against current state, or re-fetch the object from the provider's API when the payload could be stale (the common payments pattern).
- Validate payload shape (
backend-validation) — verified origin ≠ expected schema.
Outbound
- Sign payloads (HMAC + timestamp), document verification for consumers.
- Deliver via
background-jobs/queues: retries with exponential backoff, terminal-failure handling (disable + notify after N days dead), delivery log per consumer.
- Version payloads (
api-contracts); provide event IDs and a replay/reconciliation path for consumers.
- Document the unit as it is built —
docs/<app>/integrations/ (inbound and outbound contracts) (../../application-documentation).
Required Workflow
- Inventory inbound providers/events and outbound consumers/events.
- Inbound: design verify → persist → ack → async-process pipeline with dedupe + ordering strategy per event type.
- Outbound: design signing, retry schedule, delivery tracking, consumer docs.
- Specify tests: bad/missing/replayed signature rejected; duplicate event processed once; out-of-order sequence converges; outbound retry + terminal path works.
Decision Rules
- Raw-body signature verification comes before any body parsing — framework middleware order matters (
express-foundation/nestjs-foundation).
- For money-bearing events, the webhook is a trigger; the provider API re-fetch is the truth.
- Inbound processing follows
background-jobs idempotency rules; the webhook endpoint itself does no business logic.
- Outbound webhooks are a contract — shape changes follow
api-contracts breaking-change policy.
Rules
- No unverified inbound payload reaches business logic.
- Secrets per provider/consumer, rotatable (
backend-security).
- Inbound endpoints excluded from CSRF but included in rate limiting at the infrastructure margin (
rate-limiting).
Anti-Patterns
- Verifying signatures on the re-serialized parsed body.
- Doing the full state change inline, then timing out and receiving the retry.
- Trusting webhook payload data over current provider state for payments.
- No dedupe — double-crediting on redelivery.
- Outbound: fire-once, no retries, no delivery log.
Validation Checklist
Definition of Done
A recorded two-direction webhook design — verified/deduped/async inbound, signed/retried/tracked outbound — with negative tests for signature, replay, duplication, and ordering.
Related Skills
background-jobs, queues, backend-validation, backend-security, third-party-integrations, api-contracts, backend-observability, ../../application-documentation.
Related Knowledge
../../../knowledge/ (provider list, consumer contracts).
Related References
../../../references/backend/integrations/ (provider notes, when populated).
Context Loading Guidance
- Requires: provider/consumer inventory, event list, provider signature semantics.
- Does not require: unrelated endpoints, full provider SDK docs.
- May load:
background-jobs (processing), third-party-integrations (provider clients).
- Stop when: both pipelines + tests are recorded.
Token Efficiency Guidance
Design per provider/consumer as table rows (signature scheme, dedupe key, ordering strategy, retry policy); link provider docs.
1---2name: webhooks3description: Use to design webhooks in both directions — inbound (verify signatures, respond fast, process async, dedupe, handle out-of-order) and outbound (signing, retries with backoff, delivery tracking, consumer docs).4---56# Webhooks78## Purpose910Design webhook handling as the untrusted, unreliable channel it is: inbound hooks are verified, acknowledged fast, and processed idempotently; outbound hooks are signed, retried, and observable.1112## When to Use1314- Inbound: receiving events from providers (payments, messaging, git, etc.).15- Outbound: notifying customer/partner systems of your events.16- **Not** for internal service events (use `queues`).1718## Inputs1920- Provider list + their signature/retry semantics; events consumed.21- Outbound consumers + events published (`api-contracts` for payload shapes).2223## Discovery Questions2425- Inbound: what signature scheme and tolerance window does each provider use? What is the real source of truth (webhook payload vs re-fetch via API)?26- Which inbound events change money/state (payments!) — what happens on duplicate or out-of-order delivery?27- Outbound: what delivery guarantees do consumers get, and how do they recover from missed events?2829## Responsibilities3031**Inbound**32- **Verify signatures** on the raw body (before parsing/middleware mangling), with timestamp tolerance against replay; reject unverified with 4xx. Endpoint is public by necessity — signature is the gate, not obscurity.33- **Acknowledge fast, process async**: persist the event, return 2xx, hand work to `background-jobs`; provider timeouts + retries punish slow handlers.34- **Dedupe by event ID** (providers deliver at-least-once) and tolerate **out-of-order** delivery — process against current state, or re-fetch the object from the provider's API when the payload could be stale (the common payments pattern).35- Validate payload shape (`backend-validation`) — verified origin ≠ expected schema.3637**Outbound**38- Sign payloads (HMAC + timestamp), document verification for consumers.39- Deliver via `background-jobs`/`queues`: retries with exponential backoff, terminal-failure handling (disable + notify after N days dead), delivery log per consumer.40- Version payloads (`api-contracts`); provide event IDs and a replay/reconciliation path for consumers.41- Document the unit as it is built — `docs/<app>/integrations/` (inbound and outbound contracts) (`../../application-documentation`).4243## Required Workflow44451. Inventory inbound providers/events and outbound consumers/events.462. Inbound: design verify → persist → ack → async-process pipeline with dedupe + ordering strategy per event type.473. Outbound: design signing, retry schedule, delivery tracking, consumer docs.484. Specify tests: bad/missing/replayed signature rejected; duplicate event processed once; out-of-order sequence converges; outbound retry + terminal path works.4950## Decision Rules5152- Raw-body signature verification comes before any body parsing — framework middleware order matters (`express-foundation`/`nestjs-foundation`).53- For money-bearing events, the webhook is a *trigger*; the provider API re-fetch is the truth.54- Inbound processing follows `background-jobs` idempotency rules; the webhook endpoint itself does no business logic.55- Outbound webhooks are a contract — shape changes follow `api-contracts` breaking-change policy.5657## Rules5859- No unverified inbound payload reaches business logic.60- Secrets per provider/consumer, rotatable (`backend-security`).61- Inbound endpoints excluded from CSRF but included in rate limiting at the infrastructure margin (`rate-limiting`).6263## Anti-Patterns6465- Verifying signatures on the re-serialized parsed body.66- Doing the full state change inline, then timing out and receiving the retry.67- Trusting webhook payload data over current provider state for payments.68- No dedupe — double-crediting on redelivery.69- Outbound: fire-once, no retries, no delivery log.7071## Validation Checklist7273- [ ] Inbound: raw-body signature verify + replay window per provider.74- [ ] Persist → ack fast → process async pipeline.75- [ ] Dedupe + out-of-order strategy per event type (re-fetch where stale-able).76- [ ] Outbound: signing, backoff retries, delivery tracking, consumer docs.77- [ ] Negative tests: bad signature, replay, duplicate, out-of-order.7879## Definition of Done8081A recorded two-direction webhook design — verified/deduped/async inbound, signed/retried/tracked outbound — with negative tests for signature, replay, duplication, and ordering.8283## Related Skills8485`background-jobs`, `queues`, `backend-validation`, `backend-security`, `third-party-integrations`, `api-contracts`, `backend-observability`, `../../application-documentation`.8687## Related Knowledge8889`../../../knowledge/` (provider list, consumer contracts).9091## Related References9293`../../../references/backend/integrations/` (provider notes, when populated).9495## Context Loading Guidance9697- **Requires:** provider/consumer inventory, event list, provider signature semantics.98- **Does not require:** unrelated endpoints, full provider SDK docs.99- **May load:** `background-jobs` (processing), `third-party-integrations` (provider clients).100- **Stop when:** both pipelines + tests are recorded.101102## Token Efficiency Guidance103104Design per provider/consumer as table rows (signature scheme, dedupe key, ordering strategy, retry policy); link provider docs.