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 systemidempotency_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:
| Field | Whose | Use it for |
|---|---|---|
delivery.idempotency_key | Ours | Deduplicating the event. Identical across every retry, unique across every other event. |
data.call.idempotency_key | Yours | Finding 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.