Skip to main content
CallingBox emits eight event types, one for each meaningful transition on a call. Subscribe to as many or as few as you need by setting enabled_events on a webhook endpoint.

Event catalog

EventWhen it fires
call.queuedThe call has been created and credits reserved, before we dial.
call.ringingThe carrier has started ringing the destination.
call.answeredThe callee picked up; the AI session is now live.
call.completedThe call finished normally and structured output extraction is done. This is usually the event you want.
call.failedThe call ended in a provider- or AI-side failure. See error_code / error_message.
call.no_answerThe call rang out without being picked up.
call.busyThe carrier reported a busy signal.
call.canceledThe caller canceled before the remote party picked up.

Envelope shape

Every delivery carries the same wrapper:
{
  "id": "9c1d9f9e-21a1-4f6d-8fce-bf4a4b8a9e3f",
  "type": "call.completed",
  "created": 1713268800,
  "api_version": "2026-04",
  "data": {
    "call": { /* full call object */ }
  }
}
  • id — unique id for this delivery. Use it as an idempotency key.
  • type — one of the eight event types above.
  • created — unix timestamp (seconds) when CallingBox emitted the event.
  • api_version — schema version for data.call. Today this is always 2026-04.
  • data.call — the full call object as of the time of the event. Field values earlier in the lifecycle may still be null.

Which fields are populated when?

Because each event fires at a different stage, some fields are only populated later in the lifecycle:
FieldPopulated on
statusEvery event (matches the type, except queued maps to initiated once dialing starts).
started_atcall.ringing and later.
answered_atcall.answered and later.
ended_at, duration_secondsTerminal events only.
result, result_statuscall.completed only, after extraction finishes.
billed_duration_seconds, billing_amount_milli_centsTerminal events, after settlement.

Why call.completed fires after call.failed/etc, never alongside

Only one terminal event fires per call:
  • Normal hangup → call.completed after we’ve run structured output extraction, so the payload contains the final result.
  • Anything else → call.failed, call.no_answer, call.busy, or call.canceled immediately on hangup.
If you only care about “the call is done”, subscribe to all five terminal events.

Example payloads

call.queued

{
  "id": "5b9a...",
  "type": "call.queued",
  "created": 1713268790,
  "api_version": "2026-04",
  "data": {
    "call": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "queued",
      "to_number": "+15551234567",
      "from_number": "+15559876543",
      "prompt": "Confirm appointment tomorrow at 2pm",
      "result": null,
      "duration_seconds": null
    }
  }
}

call.answered

{
  "id": "5b9a...",
  "type": "call.answered",
  "created": 1713268815,
  "api_version": "2026-04",
  "data": {
    "call": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "in_progress",
      "answered_at": "2026-04-15T14:30:15Z",
      "duration_seconds": null,
      "result": null
    }
  }
}

call.completed

{
  "id": "5b9a...",
  "type": "call.completed",
  "created": 1713268860,
  "api_version": "2026-04",
  "data": {
    "call": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "completed",
      "answered_at": "2026-04-15T14:30:15Z",
      "ended_at": "2026-04-15T14:30:49Z",
      "duration_seconds": 34,
      "result": { "confirmed": true },
      "result_status": "completed"
    }
  }
}

call.failed

{
  "id": "5b9a...",
  "type": "call.failed",
  "created": 1713268820,
  "api_version": "2026-04",
  "data": {
    "call": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "failed",
      "error_code": "carrier_rejected",
      "error_message": "hangup: call_rejected",
      "result": null
    }
  }
}

Listing event types programmatically

GET /v1/webhook_events returns the current catalog. Handy in dashboards or when bootstrapping a customer onboarding flow.