Call Lens
Webhooks

call.completed

The event carrying a finished call's analysis.

Delivered when a call finishes processing.

{
  "event": "call.completed",
  "occurred_at": "2026-08-05T09:24:11Z",
  "delivery": { "idempotency_key": "3f9a1c22-...", "attempt": 1 },
  "data": {
    "call": {
      "reference": "cl_7Yx2bQ...",
      "provider": "your-dialler",
      "provider_call_id": "CALL-88213",
      "idempotency_key": "CALL-88213",
      "status": "completed",
      "direction": "outbound",
      "started_at": "2026-08-05T09:14:00Z",
      "ended_at": "2026-08-05T09:21:33Z",
      "duration_ms": 453000,
      "counterparty_e164": "+441234567890",
      "language_profile": "en-GB",
      "speaker_count": 2
    },
    "analysis": {
      "version": 1,
      "summary": "…",
      "sentiment": "positive",
      "sentiment_score": 0.62,
      "customer_intent": "…",
      "decision_maker": "…",
      "budget_state": "…",
      "timeline_state": "…",
      "outcome": "…",
      "risk_level": "low",
      "confidence": 0.81
    }
  }
}

Four things to get right

Deduplicate on delivery.idempotency_key, never on a hash of the body. delivery.attempt changes between retries, so the body changes too. Hashing it makes every retry look like a new event.

delivery.idempotency_key and data.call.idempotency_key are different fields. The first is ours and identifies the event. The second is yours, echoed back. See correlation identifiers.

analysis is null, never {}, when no analysis was produced. You must be able to tell "no analysis for this call" from "the analysis was empty". This is reachable on a call whose status is completed.

data.call.reference is the call's identifier. It is opaque and stable, and it is scoped to your organization. Call Lens does not expose internal numeric identifiers on any surface.

Fields

FieldTypeNotes
eventstringAlways call.completed.
occurred_atstringISO 8601.
delivery.idempotency_keystringDeduplicate on this.
delivery.attemptinteger1-based. Changes between retries.
data.call.referencestringOpaque, stable, per-organization.
data.call.providerstring | nullEchoed from your submission.
data.call.provider_call_idstring | nullEchoed verbatim.
data.call.idempotency_keystring | nullEchoed verbatim.
data.call.statusstringTerminal status.
data.call.directionstring | nullinbound, outbound, unknown.
data.call.started_atstring | nullISO 8601.
data.call.ended_atstring | nullISO 8601.
data.call.duration_msinteger | nullMeasured, falling back to what you reported.
data.call.counterparty_e164string | null
data.call.language_profilestring | null
data.call.speaker_countinteger | null
data.analysisobject | nullnull when no analysis exists.
data.analysis.summarystring | nullModel-generated. Unredacted — see overview.
data.analysis.sentimentstring | null
data.analysis.sentiment_scorenumber | null
data.analysis.customer_intentstring | null
data.analysis.decision_makerstring | null
data.analysis.budget_statestring | null
data.analysis.timeline_statestring | null
data.analysis.outcomestring | null
data.analysis.risk_levelstring | null
data.analysis.confidencenumber | null

On this page