Skip to main content

Outbound Webhooks (v1)

FieldValue
StatusDeferred. Not included in any current tier.
OwnerUnassigned
Target reposattunelogic-api, attunelogic-service
RelatedMonetization & Tier Packaging (v1), Public API (v1), Feature Roadmap Index
Last updated2026-04-23

Status banner: Outbound webhooks were removed from the public Growth tier. The platform accepts inbound webhooks today (Stripe) via src/controllers/webhooks/*, but no outbound delivery pipeline exists.


Why this was removed from v1

  • Nothing about outbound delivery is built yet: no endpoint CRUD, no event catalog, no HMAC signing, no delivery queue, no retries, no dead-letter inspection UI.
  • "Webhooks" on the previous Growth card implied a production-grade delivery promise we couldn't keep on launch day. Shipping it half-done would have created a support hole (missed deliveries, no retry visibility) that's worse than not shipping at all.

What shipping this requires

Data model

  • New WebhookEndpoint model scoped by parentCompany:
    • url: string
    • description: string
    • events: string[] (subscribed event names; validated against the catalog)
    • secret: string (HMAC signing secret; shown once on create, hashed at rest)
    • active: boolean
    • failureCount: number
    • disabledAt: Date
    • createdBy, createdAt, updatedAt
  • New WebhookDelivery model scoped by parentCompany:
    • endpointId, event, payload (snapshot), status (pending / delivered / failed / dead), attempts: number, lastAttemptAt, nextAttemptAt, responseCode, responseBody (truncated), durationMs.

Event catalog

Initial ship-with-v1 catalog (all scoped by parentCompany):

  • job.created, job.updated, job.status_changed, job.cancelled
  • leg.status_changed
  • invoice.created, invoice.finalized, invoice.paid
  • driver.created, driver.deactivated
  • lead.created

Each payload wraps the resource with { id, version, event, createdAt, tenant: { id }, data: {...} } so subscribers can idempotency-key on id.

API surface

  • GET /api/v1/webhooks/endpoints
  • POST /api/v1/webhooks/endpoints
  • PATCH /api/v1/webhooks/endpoints/:id
  • DELETE /api/v1/webhooks/endpoints/:id
  • GET /api/v1/webhooks/deliveries?endpointId=…
  • POST /api/v1/webhooks/deliveries/:id/retry
  • Feature gate: existing requireFeature middleware + tenant-config flag webhooks.outbound.enabled.

Delivery pipeline

  • Event producers publish to an internal event bus (simple: emit → enqueue a job per active matching endpoint).
  • Worker fires HTTP POST with:
    • Content-Type: application/json
    • X-AttuneLogic-Signature: t=<unix>,v1=<hmac_sha256>
    • X-AttuneLogic-Event: <event>
    • X-AttuneLogic-Delivery: <deliveryId>
  • Retry schedule: 1min, 5min, 30min, 2h, 6h, 12h, 24h (exponential). After 7 failures the endpoint is auto-disabled and the tenant admin is emailed; manual re-enable required.
  • Per-endpoint circuit breaker: 10 consecutive failures in 1h trips the breaker for 1h.

Service web UI

  • Settings → Developers → Webhooks:
    • Endpoint CRUD (URL, description, subscribed events matrix).
    • Signing-secret "reveal once then rotate" UX.
    • Delivery log with status, response code, response body preview, and manual retry.
    • Event-catalog reference docs surfaced inline.

Security

  • Tenant isolation: every read/write hard-scoped by parentCompany. An endpoint in one tenant can never see deliveries from another.
  • HMAC signatures are per-endpoint (no shared global secret).
  • Outbound SSRF hardening: block RFC1918, loopback, metadata service IPs, and a tenant-configurable allowlist host policy.
  • Rate limit: cap per-tenant deliveries at a reasonable ceiling (e.g. 10k/day) to prevent runaway-fanout from killing us or the subscriber.

Tests

  • Unit: signature generation + verification round-trip. Retry backoff schedule. Auto-disable threshold.
  • Integration: happy-path deliver, 500 → retry, 410 → auto-disable (tenant explicitly rejected), 429 → respect Retry-After, private-IP target refused.
  • Tenant isolation: a job event in tenant A never fans out to endpoints owned by tenant B.

Docs

  • Customer-facing "Webhooks setup" guide.
  • Developer event-reference page (auto-generated from the catalog).
  • Runbook: rotating a leaked signing secret.

Dependencies on existing infra

  • Feature flag registrywebhooks.outbound.enabled is already reserved as a future flag in the monetization proposal.
  • Job queue — existing agenda/bull queue handles retry scheduling.
  • AuditLog — already landed; endpoint CRUD + secret rotation are natural audit events.
  • Public API (v1) — this proposal and Public API share the developer-settings IA in the service web UI.

Estimated timeline and risk

  • Effort: 3 weeks end-to-end for one engineer (backend + UI + docs). Retry + dead-letter is where edge cases live.
  • Risk: Medium-high. Delivery reliability is a customer-trust feature; shipping it without alerting + a manual retry UI is not an option.

Open questions

  • Do we need per-event filters (e.g. "only job.status_changed where status = delivered") in v1, or is that v2?
  • Do we support JSON Schema for payload validation so customers can lint against our shapes?
  • Do we publish an "events API" (GET a paginated log of past events) as a supplement to webhooks, for customers who prefer polling?

Cross-references