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:
{
  "call_id": "call_8f9b2c1e-4a5d-4f6e-8b1a-2c3d4e5f6a7b",
  "payload": { /* one of the variants below */ }
}
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.
{
  "call_id": "call_8f9b2c1e-4a5d-4f6e-8b1a-2c3d4e5f6a7b",
  "payload": {
    "type": "complete",
    "call_started": "2026-04-12T10:30:05Z",
    "call_data": {
      "call_id": "call_8f9b2c1e-…",
      "direction": "outbound",
      "phone_number": "+966512345678",
      "status": "completed",
      "total_duration": 47,
      "enhanced_transcript": {
        "transcript": { "messages": [ /* user + assistant turns */ ] },
        "errors": []
      },
      "report": { /* scenario-specific structured output */ },
      "recording_url": "https://storage.googleapis.com/…?signature=…",
      "created_at": "2026-04-12T10:30:00Z",
      "started_at": "2026-04-12T10:30:05Z",
      "ended_at": "2026-04-12T10:30:52Z"
    },
    "response_body": { /* optional, scenario response */ }
  }
}
recording_url is a signed, time-limited URL. Download promptly or generate a fresh one via GET /calls/{call_id}.

Not-completed call

Fires when the call never reached the customer. type indicates why:
typeMeaning
no_answerRang, no pickup
user_rejectedCustomer hung up / rejected the call
user_unavailableCarrier returned unavailable (off, out of coverage)
automationHit an IVR / voicemail / non-human
failedTelephony failure with no SIP-level reason
{
  "call_id": "call_8f9b2c1e-4a5d-4f6e-8b1a-2c3d4e5f6a7b",
  "payload": {
    "type": "no_answer"
  }
}

Retries

Sarj.ai retries up to 3 times on failure (network error, timeout, non-2xx response) with a 2-second delay between attempts. Each attempt has a 10-second timeout. After 3 failures the delivery is marked failed and 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 May 17, 2026