Skip to main content
When a request reaches a terminal state, SuperDial sends an HTTP POST to your webhook endpoint with the result. Webhooks are the recommended way to consume request results.

When webhooks fire

A webhook is sent once per request, when its state becomes one of: No webhook is sent while a request is still PROCESSING.

Configuration

You can set your webhook endpoint in two places:

Account default

Set your account-level Request webhook URL in the SuperDial portal: go to API, find the Webhooks section, and fill in Request webhook. Once configured, this becomes the default for every request you create. No per-request webhookUrl field needed.
The Requests API uses a different webhook URL from the legacy Calls API. In the same Webhooks section, your legacy URL appears separately as Legacy webhook URL (/v1/calls). Setting one does nothing for the other, and there is no fallback between them. If you are moving from POST /v1/calls to POST /v1/requests, set the Request webhook URL before you cut traffic over, or your requests will complete and deliver nothing.
To confirm delivery is working, the same panel shows Recent deliveries (7 days), filterable by Request ID. If you have submitted requests and that list is empty, the URL is not set correctly.

Per-request override

Pass a webhookUrl field in the body of POST /v1/requests to direct a single request to a different URL. The per-request value always wins over the account default.
If neither is configured, no webhook is sent and no error is raised. Delivery is a silent no-op: requests reach a terminal state normally, and nothing tells you the results went nowhere. Poll GET /v1/requests/{requestId} for results until a URL is set.

Payload

The webhook body is intentionally compact. To get the full result (results, missingFields, modality, data_completeness, and the error object on non-SUCCESS), call GET /v1/requests/{requestId} after receiving the webhook.
By the time you receive the webhook, the request is fully readable. For phone-backed requests, the call enrichment fields (transcript, recordingDownloadUrl, callDuration, callSummary) are available on the GET /v1/requests/{requestId} response.

Signature verification

Every webhook delivery includes an X-Webhook-Signature header. Verify it on every delivery. Without verification, anyone who learns your endpoint URL can forge events. The signature is HMAC-SHA256 of the raw request body. The signing secret depends on which credentials created the request: Compute the HMAC over the raw body bytes exactly as received: do not parse and re-serialize the JSON, since that changes the byte sequence and breaks the signature. The header value is the bare 64-character lowercase hex digest, with no sha256= prefix or other framing. Example:

Python

Node.js

Both samples use a constant-time comparator (hmac.compare_digest / crypto.timingSafeEqual); use the equivalent in your language rather than == to avoid timing-attack risk. The signature doesn’t include a timestamp, so it can’t be used to detect replays on its own. Use requestId as a dedup key (see Idempotency below).

Delivery and retries

We send the webhook when the request reaches a terminal state. Delivery has two layers. Inline retries. On a 5xx response or connection failure we retry up to 3 more times (4 attempts total) with exponential backoff (0.5s → 1s → 2s). Each attempt times out after 10 seconds. Later retries. If all four inline attempts fail, we try the delivery again later. A request gets up to 3 delivery rounds in total, within 7 days of reaching its terminal state. How we treat each response: Once all three rounds are used, the failure is recorded and no further attempts are made. Fall back to polling GET /v1/requests/{requestId} to recover. For high-reliability ingestion:
  • Ack with 2xx as soon as you’ve durably enqueued the event for processing.
  • Track the requestIds you’ve submitted on your side. Any request whose terminal outcome you haven’t received within the expected window should trigger a fallback poll.

Idempotency

In rare cases the same requestId may arrive more than once. Always treat requestId as a dedup key:
If you also passed internalId when creating the request, you have two layers of dedup keys. Pick whichever fits your system. Return HTTP 200 as quickly as possible. Don’t do synchronous work that could exceed our 10-second timeout. Push processing to a background job and ack immediately. 5xx responses and connection failures trigger automatic retries. A 400 or 404 stops delivery permanently (see Delivery and retries above). If all retries are exhausted, fall back to polling GET /v1/requests/{requestId} to recover. After acking, call GET /v1/requests/{requestId} to fetch the full payload (results, missingFields, modality, and the error object on FAILURE).