Skip to main content
When a call reaches a terminal state, Sarj.ai POSTs a JSON payload to your configured webhook URL. You don’t need to poll getCall — webhooks push the same data the moment it’s available.

Configure

Set your webhook URL in the Sarj.ai Dashboard (one URL per organization). The endpoint must:
  • Be reachable over HTTPS (HTTP also works for staging, not recommended for production)
  • Return 2xx within 10 seconds
  • Be idempotent — see Retries below

Payload

Every notification has the shape:
payload.type discriminates the variant.

Completed call (type: "complete")

Fires when the call reached the customer and finished. Includes the full recording URL, transcript, and report.
permanent_recording_url is a stable Sarj URL authenticated with the same API key as the call API. Resolve it when you need a fresh download redirect. Older webhook payloads can also include the deprecated, short-lived recording_url.

Not-completed call

Fires when the call never reached the customer — every attempt reports its outcome, including busy, no-answer, and dial failures. type indicates why:

Retry attempts

When retries are configured, each dial is its own call with its own webhook, linked by the attempt fields present on both payload variants: A typical retried contact looks like: attempt 1 no_answer with next_retry_at set, attempt 2 user_rejected with next_retry_at set, attempt 3 complete with next_retry_at: null.

Retries

Sarj.ai makes up to 3 delivery attempts per call, a few seconds apart, each with a 5-second timeout. A 4xx response other than 408 or 429 is treated as a permanent rejection and is not retried. After delivery is exhausted or permanently rejected, the per-call webhook state is recorded server-side. You can re-fetch the call detail via GET /calls/{call_id} at any time — the data is durable.
Your endpoint must be idempotent. The same call_id may arrive more than once if your server’s 2xx response is delayed or dropped. Deduplicate on call_id.

Verifying authenticity

Webhook signature verification (HMAC) is not yet shipped. For now, lock down your webhook endpoint by IP allow-listing (contact support for the current source IP range) or by adding a hard-to-guess secret path component to the URL (e.g. https://your-app.com/webhooks/sarj/c8f4a2b6e1d…).

Testing

The dashboard offers a “Send test webhook” button to fire a synthetic complete payload at your URL — use this while standing up the integration. After that, place a real test call to verify end-to-end.
Last modified on September 23, 2026