Skip to main content
Inbound webhooks let external systems — Five9, Stripe, anything that can POST — trigger a definition. An admin creates a webhook config bound to an active definition; the external sender POSTs signed deliveries to a per-customer receive URL; each verified delivery starts a normal job (source: "webhook", with webhook_id + delivery_id in the job metadata).
This surface is inbound-only. Outbound webhooks — workflow tasks calling external URLs — are a separate future REST catalog action, not receiver machinery.
{
  "id": "8a9c86a8b78c48d3a3e5e00ad0ed5b96",
  "definition_id": "def_a1b2c3d4",
  "description": "Five9 call-completed events",
  "mode": "trigger",
  "provider": "standard",
  "enabled": true,
  "receive_url": "/webhooks/acme/8a9c86a8b78c48d3a3e5e00ad0ed5b96"
}

The webhook object

FieldTypeDescription
idstring128-bit opaque hex identifier — the receive URL is unguessable by construction.
definition_idstringDefinition to trigger. Must belong to your org and be re-validated as active at dispatch time.
org_idstringOwning organization.
descriptionstringHuman-readable description (1–200 chars).
modestringtrigger (each delivery starts a new job). resume is reserved and rejected with 422. Immutable after create.
providerstringSignature-verification adapter. Only standard (Standard Webhooks HMAC-SHA256) is implemented; stripe/five9/custom are rejected with 422. Immutable after create.
input_templateobject | nullOptional {{ }}-expression mapping from the normalized payload context to the definition’s input_data. Omit to pass the whole normalized payload through.
dispatch_retryobject | nullAdmin-authored dispatch retry policy, default OFF (one attempt), e.g. {"max_attempts": 3, "backoff": 5}. Never read from the sender’s body.
rate_limitinteger | nullPer-webhook deliveries/minute cap. Default 1000.
enabledbooleanfalse makes the receive URL answer 404.
signing_secretstringShow-once. Returned only on create and rotate — never retrievable from any GET. Store it in the sending system immediately.
receive_urlstringShow-once relative path. Prepend https://api.getdialed.ai/flows before handing it to a sender.

The receive URL

The receiver path is POST /webhooks/{slug}/{webhook_id}. In production the Flows API mounts under the /flows ingress prefix, so the URL external senders must call is:
https://api.getdialed.ai/flows/webhooks/{slug}/{webhook_id}
The receive_url returned at create time is a relative path (no host, no /flows prefix) — prepend https://api.getdialed.ai/flows when configuring your sender. The {slug} identifies your tenant; the 128-bit {webhook_id} is unguessable.

Signature verification

The receiver carries no X-API-Key / Authorization requirement — the trust boundary is the HMAC-SHA256 signature over the raw request body, verified per the Standard Webhooks spec before the body is parsed. Every sender must sign each delivery with the webhook’s signing secret, or the delivery is rejected with 401.
Senders include three Standard Webhooks headers on every delivery:
HeaderDescription
webhook-idSender-chosen unique delivery ID. This is the idempotency key — re-sending the same value is safe.
webhook-timestampUnix seconds. Deliveries outside the 5-minute replay window are rejected with 401.
webhook-signaturev1,<base64 HMAC-SHA256> computed over {webhook-id}.{webhook-timestamp}.{raw body} with the signing secret.
The 401 message is deliberately generic — a missing header, an expired timestamp, a tampered body, and a wrong secret all return the same {"detail": "Signature verification failed"}, revealing nothing to a probing caller. Existence failures (unknown slug, unknown webhook_id, or a disabled webhook) always return 404, never 401.

Delivery semantics

  • 202-async. The receiver acknowledges within ~50ms with 202 Accepted; job creation and dispatch happen asynchronously after the ack. Check the deliveries view for the outcome.
  • Deduplication. Exactly one job per webhook-id. A replayed delivery returns 202 but does not dispatch again — sender retry storms collapse to one job.
  • Rate limit. Each webhook accepts up to rate_limit deliveries/minute (default 1000/min), counted per webhook_id (not per source IP, so senders sharing egress IPs don’t throttle each other). Over-limit deliveries get 429.
  • Body format. Content-Type drives normalization — JSON is parsed, form-urlencoded becomes a dict, XML is parsed with a hardened parser, anything else is wrapped as {"raw": ..., "content_type": ...}. The receiver never rejects on format.

Managing webhooks

All management endpoints require authentication and operate only on your organization’s webhooks. Mutating endpoints require an admin-role caller (an X-API-Key is admin-equivalent).
MethodEndpointPurpose
POST/webhooksCreate a config and mint its signing secret. Returns 201 with the show-once signing_secret + receive_url.
GET/webhooksList your org’s webhooks with cursor pagination. The secret never appears on the read model.
GET/webhooks/{webhook_id}Fetch one config (no secret, no receive URL).
PATCH/webhooks/{webhook_id}Partial update — rebind definition_id, edit description/input_template/dispatch_retry/rate_limit/enabled. mode/provider are immutable.
POST/webhooks/{webhook_id}/rotate-secretRotate the signing secret with a 24-hour previous-secret overlap. Returns the new secret once.
DELETE/webhooks/{webhook_id}Delete the config and scrub its stored signing secret. Returns 204.
GET/webhooks/{webhook_id}/deliveriesRecent deliveries — the debugging view for “did my sender’s POST arrive and start a job?”.
POST/webhooks/{slug}/{webhook_id}The receiver — called by your external system, HMAC-signed, no API key. Returns 202.
Creating one:
curl -X POST "$BASE_URL/webhooks" \
  -H "X-API-Key: $GETDIALED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "definition_id": "def_a1b2c3d4",
    "description": "Five9 call-completed events"
  }'
The signing_secret is returned exactly once — on create and on rotate-secret. Rotation keeps the previous secret valid for 24 hours so you can migrate senders without a hard cutover. If you lose a secret, rotate to mint a new one rather than recreating the webhook (which would change the receive URL).

Next steps

Receive webhooks

A step-by-step walkthrough: create a webhook, sign a delivery, and confirm the job.

Event subscriptions

Trigger definitions from internal business events instead of external POSTs.