Submit a call
Authorization
ApiKey ingestAuthorization: Bearer clk_{tenant_id}_{secret}. The header X-Api-Key carrying the same value is also accepted, for integration platforms that cannot set an Authorization header. Keys are minted in the Callens dashboard.
In: header
Scope: ingest
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Every call names the employee it belongs to. Send exactly one of employee_code and employee_id. A request that sends neither, or both, is refused with 422.
Every call names the employee it belongs to. Send exactly one of employee_code and employee_id. A request that sends neither, or both, is refused with 422.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/calls" \ -H "Content-Type: application/json" \ -d '{ "mode": "upload", "upload_ticket": "eyJpdiI6…", "started_at": "2026-08-05T09:14:00Z", "employee_code": "EMP-1042", "provider": "zoom", "provider_call_id": "CA123", "idempotency_key": "CA123" }'{ "success": true, "message": "Call already ingested.", "data": { "id": "string", "status": "string" }}Request somewhere to upload a recording POST
Returns a short-lived presigned `PUT` URL and an opaque `ticket`. Send the audio bytes straight to `upload.url` — they never pass through Callens — then submit the call with `POST /calls`, `mode: "upload"` and the ticket. The `upload.headers` map must be applied to the `PUT` verbatim; it is empty against some storage backends and required by others, so a client that ignores it will fail with a signature mismatch in production only.
Submit a customer event POST
Records one thing that happened with a customer outside a Callens call — a message, an order, a note — from any system. One event per request. Callens recognises the customer from the identifiers in `customer` and stores the event on that customer. `event.content` is kept as descriptive text and is never parsed into fields. Sending the same `event.source` and `event.external_id` again returns the stored event and writes nothing, so the id must be the same on every retry of one event. Call this from a server you control and never from a browser or a mobile app: the response says whether an identifier already belongs to one of your customers and returns that customer's id, so a key with the `events` scope must not be readable by an anonymous client.