Call Lens
Ingesting calls

Correlation identifiers

The two fields that let you match an event to your own record.

Two fields on POST /calls are echoed back verbatim on every call.completed event:

  • provider_call_id — the call's identifier in your system
  • idempotency_key — your identifier for the submission

They are the entire mechanism for joining a Call Lens event to a record in your CRM. You submit them; we hand them back untouched; you join on them.

They become required on keys with webhooks enabled

If your API key has webhooks enabled, both fields are required rather than optional. A 422 naming them means exactly this.

The reason is direct: a webhook-enabled key submitting calls without correlation identifiers produces events that cannot be matched to anything. The call is processed, the analysis is produced, the event is delivered — and there is no way to tell which of your records it belongs to. Requiring the fields at submission is the only point where that is still fixable.

This requirement is enforced per key. Delivery itself is decided per organization — read the next section before assuming a key without the flag is safe to omit these fields on.

Delivery does not check which key ingested the call

Webhook delivery has nothing to do with which key submitted the call. When a call reaches completed, Call Lens sends call.completed to every active endpoint your organization has registered — that decision is made purely from the organization's outbound_webhooks rows, with no reference to the key, or even whether a key was involved, that ingested the call.

That has a consequence worth stating plainly: if your organization has any active webhook endpoint, every call your organization ingests generates an event — including calls ingested through a key that does not have webhooks enabled and was never asked for provider_call_id or idempotency_key. Nothing refuses that call at ingest. It is processed and an event ships for it like any other; the event just carries nothing you can join to your own record.

The per-key flag only controls one thing: whether the ingest API requires the two fields on that key. It is a guardrail against forgetting on a key you've deliberately marked strict — not the switch that turns delivery on or off. That switch is "does my organization have an active endpoint," and every key you hold shares the same answer to it.

The practical rule: if your organization has an active webhook endpoint, send provider_call_id and idempotency_key on every key you ingest through — not only the ones that reject the request without them.

Do not confuse the two idempotency keys

The call.completed payload contains two fields with that name, in different places:

FieldWhoseUse it for
delivery.idempotency_keyOursDeduplicating the event. Identical across every retry, unique across every other event.
data.call.idempotency_keyYoursFinding your own record. Exactly the value you submitted.

They are namespaced rather than renamed because renaming the echo would stop it being an echo — you must be able to find the field you submitted under the name you submitted it under.

On this page