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 batch (trigger_type: "webhook", with webhook_id + delivery_id in the batch metadata).
This surface is inbound-only. Outbound webhooks — workflow tasks calling external URLs — are a separate future REST catalog action, not receiver machinery.
Not to be confused with the inbound-email receiver. Delivering an email reply back into a parked send-and-wait step uses a different endpoint that has nothing to do with the machinery on this page.Everything on this page — creating a config, holding a signing secret, rotating it, reading deliveries — applies to the webhook trigger and to nothing else. The reply path is set up as part of enabling inbound mail on a sending domain; see human in the loop.

The webhook object

The receive URL

The receiver path is POST /flows/webhooks/{slug}/{webhook_id}. In production the API is served under the /v1 base, and webhooks live in the flows product group, so the URL external senders must call is:
The receive_url returned at create time is a relative path: it omits the host and the /v1 version segment, but it does include its /flows group. So prepend https://api.getdialed.ai/v1 — host and version only — when configuring your sender, and do not add /flows a second time. 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: 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; batch creation and dispatch happen asynchronously after the ack. Check the deliveries view for the outcome.
  • Deduplication. Exactly one batch per webhook-id. A replayed delivery returns 202 but does not dispatch again — sender retry storms collapse to one batch.
  • 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). Creating one:
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 batch.

Event subscriptions

Trigger definitions from internal business events instead of external POSTs.