This capability is granted by an API key scoped to the webhooks product (product face). See the product reference below.
Multi-tenant, resilient webhook egress. POST a delivery job; the service durably queues, signs (HMAC-SHA256), retries (exp-backoff + jitter, honoring Retry-After), circuit-breaks per (org, target-host), SSRF-guards, and audits every attempt to Postgres. The HMAC signing secret is resolved server-side per org (EGRESS_SECRET__<ORG> -> EGRESS_DEFAULT_SECRET, Infisical-rendered) — never accepted in-body, never persisted.
v1.1 (additive, backward-compatible expand-contract): a SUBSCRIPTION REGISTRY + event-type FAN-OUT. Register endpoints (/v1/endpoints) subscribed to event_types (or '*'), then emit an event (/v1/events) and the service fans it out to every matching active endpoint — each fanned delivery is a normal durable, signed, retried delivery. Ported from vagary-platform's webhook_delivery_service subscription model + content_syndication partner fan-out.
v1.2 (additive, S3 merge-gap — absorbs the vagary-platform model so the platform's webhook registry can be retired losing nothing): (a) owner_id — a WITHIN-org per-user scope (organization_id stays the outer tenant, I6). CRUD-by-id is owner-STRICT (a wrong/absent owner cannot read/update/delete an owner-set endpoint — closes the platform cross-owner AUTHZ bug); fan-out/list are owner-OPT-IN (omit = all owners in the org). Supply owner via the X-Owner-Id header or an owner_id body field. (b) signing_mode — 'org_timestamp' (DEFAULT, stronger: HMAC(per-org-secret, "<ts>.<body>") + X-Webhook-Timestamp, secret never persisted) or 'endpoint_body' (vagary-platform compat: HMAC(per-endpoint-secret, body), header 'X-Webhook-Signature: sha256=<hex>', no timestamp) with a required per-endpoint signing_secret. The per-endpoint secret is write-only — accepted on register / rotated on patch, NEVER echoed in any response.
- Group: Comms & workflow
- Contract:
contracts/webhook-egress/v1/openapi.yaml
- Public base:
https://api.vagarylabs.com (the consolidated API gateway — one host, per-brand sibling api.<zone>)
- Auth: a product API key (
vgk_…) issued from the console — Authorization: Bearer vgk_…
- Product face (customer-keyed):
https://api.vagarylabs.com/product/v1/webhooks/deliveries
- Capability face (internal first-party — NOT customer-keyed):
https://api.vagarylabs.com/v1/deliveries
Endpoints
| Method | Path | Summary |
|---|
POST | /v1/deliveries | Enqueue a durable, signed, audited delivery job |
GET | /v1/deliveries/{id} | Delivery status (terminal or in-flight) |
POST | /v1/endpoints | Register a subscription endpoint for event-type fan-out |
GET | /v1/endpoints | List the org's subscription endpoints (active and paused) |
GET | /v1/endpoints/{id} | One subscription endpoint (org-scoped) |
PATCH | /v1/endpoints/{id} | Update a subscription endpoint (url / event_types / active — org-scoped) |
DELETE | /v1/endpoints/{id} | Deactivate a subscription endpoint (soft-delete, org-scoped) |
POST | /v1/events | Emit an event-type; fan out to every matching active subscription |
GET | /health | DB reachability gate (open — no auth) |
GET | /metrics | Prometheus text exposition (open — fleet scrape + healthcheck) |
Product face
The external, paying-customer surface served by the edge at /product/v1/* (contracts/webhook-egress/product/v1/openapi.yaml).
| Method | Path | Summary |
|---|
POST | /deliveries | Enqueue a durable, signed, audited webhook delivery (managed, metered) |
Schemas
EnqueueRequest
| Field | Type | Description |
|---|
organization_id | string | PRODUCT-TIER end-customer tenant (I6). Defaults to the service default_org if omitted. |
owner_id | string | optional WITHIN-org owner (per-user) audit dimension; may also be supplied via X-Owner-Id. |
url | string | delivery target (SSRF-guarded — private/loopback/link-local/metadata ranges rejected) |
event_type | string | |
payload | object | JSON object, <= 512 KiB serialized |
custom_headers | object | |
idempotency_key | string | dedup key — a repeat returns 200 with deduplicated=true |
max_attempts | integer | clamped to [1,20]; defaults to the service delivery.maxAttempts |
EnqueueAccepted
| Field | Type | Description |
|---|
delivery_id | string | |
organization_id | string | |
status | object | |
idempotency_key | string | |
deduplicated | boolean | |
DeliveryRecord
| Field | Type | Description |
|---|
delivery_id | string | |
organization_id | string | |
owner_id | string | WITHIN-org owner (per-user) if the delivery was owner-scoped |
url | string | |
event_type | string | |
status | object | |
attempts | integer | |
max_attempts | integer | |
last_response_code | integer | |
last_error | string | |
endpoint_id | string | source subscription for a fanned delivery (null for a direct enqueue) |
signing_mode | object | |
next_attempt_at | string | |
created_at | string | |
updated_at | string | |
DeliveryStatus
SigningMode
org_timestamp (default, stronger): HMAC(per-org-secret, "<timestamp>.<body>"), header X-Webhook-Signature=<hex> + X-Webhook-Timestamp, secret resolved server-side per org and never persisted. endpoint_body (vagary-platform compat): HMAC(per-endpoint-secret, body), header X-Webhook-Signature=sha256=<hex>, no timestamp.
RegisterEndpointRequest
| Field | Type | Description |
|---|
owner_id | string | optional WITHIN-org owner (per-user); may also be supplied via the X-Owner-Id header. Owner-set endpoints are owner-strict on CRUD-by-id. |
url | string | subscription target (SSRF-guarded at both register and delivery time) |
event_types | array | event types this endpoint receives; a single '*' subscribes to all events |
signing_mode | object | |
signing_secret | string | REQUIRED when signing_mode='endpoint_body' (the per-endpoint HMAC secret); rejected otherwise. Write-only — never returned in any response. |
UpdateEndpointRequest
partial update — any subset of the whitelisted fields. signing_mode is immutable after creation; only the per-endpoint signing_secret may rotate.
| Field | Type | Description |
|---|
url | string | |
event_types | array | |
active | boolean | false pauses the endpoint without deleting it |
signing_secret | string | rotate the per-endpoint secret (endpoint_body endpoints). Write-only — never returned. |
Endpoint
| Field | Type | Description |
|---|
endpoint_id | string | |
organization_id | string | |
owner_id | string | WITHIN-org owner (per-user) |
url | string | |
event_types | array | |
active | boolean | |
signing_mode | object | |
created_at | string | |
updated_at | string | |
Generated by scripts/gen-capability-docs.py from contracts/webhook-egress/v1/openapi.yaml — the contract IS the source of truth; edit the contract, not this page.