Skip to main content

Request Payloads

These are the JSON payloads your webhook endpoint will receive for different events.

Call Started Event

Triggered when a call is registered and queued for dialing — before it connects. At this point the call has not been placed yet, so call_sid, called_on, and all latency/cost fields are still null, and the status is registered / QUEUED (not ongoing / ACCEPTED).
The overwhelming majority of call_started events carry status: "registered", sub_status: "QUEUED". An ongoing / ACCEPTED variant is emitted only for the subset of calls that connect quickly enough to publish a second call_started. Design your handler around registered / QUEUED.

Call Completed Event

Triggered when a call attempt finishes — this fires for every terminal outcome, not just successful conversations: completed, failed, error, cancelled, forwarded, and interim retry. On non-completed outcomes the transcript is usually empty, call_duration / latency / cost are null, and sub_status carries the reason (see the Status & Sub-Status Reference section below).
attempts is the per-dial history for this call (one entry per telephony attempt, oldest first). Each entry’s status is the raw, original-cased outcome of that attempt (e.g. "Busy Line", "ACCEPTED") — the top-level sub_status is the lowercased form of the final attempt’s reason. calling_source (the telephony provider, e.g. "plivo") is also included on a growing share of calls.

Recording Completed Event

Triggered when call recording is processed and ready for download.
The recording_url is valid for 24 hours after the call. Download and store the recording within that window if you need to retain it.
Unlike the other events, recording_completed does not include status, agent_id, workspace_id, version_slug, or version_description. It does carry sub_status.

Platform Analysis Event

Triggered when Ringg AI’s built-in analysis completes.
Analysis events are emitted for the call regardless of outcome, so the top-level status / sub_status reflect the call result (e.g. failed / busy line, or error / not_able_to_call), not the analysis. For calls that never connected there is no conversation to analyse, so analysis_data is empty or minimal. Use analysis_data.status (analyzed) to tell whether analysis actually ran.

Client Analysis Event

Triggered when your custom analysis completes based on your configured prompts.

All Processing Completed Event

Triggered once all post-call processing is finished — recording uploaded, transcript generated, and both platform and client analysis complete. This single consolidated event carries the full call dataset in one payload.

Linking Retries and Callbacks to the Original Call

Some calls are placed automatically on behalf of an earlier one — a scheduled callback, a retry after a failed attempt, or a redial after voicemail was detected. These are separate calls with their own call_id, and they emit their own full set of webhooks. To let you stitch them back together, such a call carries parent_call_id: the call_id of the call it was created from.
The key is always present. For a call that was dialled directly it is sent as null, the same as every other optional field — you never have to distinguish “no parent” from “an older payload that didn’t carry the field”.
Behaviour worth knowing:
  • It appears on every event type — call_started, call_completed, recording_completed, both analysis events, and all_processing_completed — so you can link a child call as soon as it starts, without waiting for post-call processing.
  • It is null, never absent, when there is no parent — so a plain payload["parent_call_id"] read is safe, and parent_call_id != null is a complete test for “this call came from another”.
  • It is never equal to the event’s own call_id. If you were previously deriving parentage some other way, note that a call is never its own parent in this field.
  • The chain shape depends on why the call was placed, so do not assume either one:
    • Scheduled callbacks are flat — every callback attempt for a call carries the same parent_call_id, pointing at the original call. Two callbacks in a row are siblings, not parent and child.
    • Voicemail redials are nested — each attempt points at the attempt immediately before it, so a chain can be several levels deep.
    To find the original call reliably under both shapes, follow parent_call_id upward until the field is absent, and bound the walk so a long redial chain cannot loop.
  • A parent_call_id does not by itself mean “callback”. Retries and voicemail redials carry one too. There is no separate flag on the webhook to distinguish them; use the call-history API if you need the specific category.

Status & Sub-Status Reference

Every call event carries a status and a sub_status (except recording_completed, which carries only sub_status). status is the call’s lifecycle state; sub_status refines it. The tables below reflect the values actually observed on delivered webhooks across a recent production window.

status

sub_status

The sub_status you receive depends on the status. On registered / retry (i.e. call_started): QUEUED. On ongoing: ACCEPTED. On completed — delivered uppercase, as-is: On cancelled: On failed / errorsub_status is the telephony carrier’s hangup-cause name, lowercased (a few Ringg-internal reasons, also lowercased, appear here too). It is not the short enum you might expect (busy, no-answer, …) — carriers such as Plivo return human-readable phrases. Values observed in production:
The failed / error list is provider-specific and open-ended — the exact strings depend on the telephony provider (Plivo, Twilio, Exotel, Vobiz, …), so treat this sub_status as a free-form lowercased string, not a fixed enum. The original-cased reason for each dial attempt is also available under call_completed’s attempts[].status.

Implementation Examples

Node.js/Express

Field Descriptions

Common Fields

Call Started Fields

Fired when the call is registered and queued, before it is placed. Because the call hasn’t connected yet, call_sid, called_on, created_at, call_cost, and the latency fields are typically null at this point.

Call Completed Fields

Recording Fields

Analysis Fields

The analysis events (platform_analysis_completed, client_analysis_completed) fire for the call regardless of outcome, so their top-level status / sub_status describe the call result, not the analysis. Whether analysis actually ran is inside analysis_data.status.

All Processing Completed Fields

This event combines all data from the call lifecycle into a single payload. It includes every common field plus: