Send a call
POST https://ingest.voix.tech/submitA single endpoint accepts every call. It is authenticated with your API key and takes a JSON body describing the call.
The two beats
Most phone systems know about a call in two moments: when it starts and when it ends. The Ingest API is built around that, you can submit the same call twice, and VOIX stitches the two into one record.
Beat 1: call started
Send the call’s metadata as soon as it begins, without a recording. This registers the call so it shows up immediately.
{
"callId": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
"from": "+31612345678",
"to": "+31201234567",
"startTime": "2026-06-16T09:05:35.000Z",
"outgoing": false
}Response:
{ "status": "received", "callId": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed" }Re-send the stable fields on both beats. Always include from, to,
startTime, and outgoing on beat 2 as well, not just the new fields. VOIX
matches the two submissions by callId and takes the latest values, so
re-sending them keeps the record correct without depending on what was stored
the first time.
One beat is fine too
The two beats are a convenience, not a requirement. If your system only learns
about a call once it is over, just send everything in a single request with the
recordingUrl included. VOIX skips straight to transcribing.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
callId | UUID | Yes | Your stable identifier for the call. Reused across both beats and for any retry. Acts as the idempotency key. |
recordingUrl | URL | On the finishing beat | A URL VOIX can fetch the recording from. Its presence is what triggers transcription. |
from | string | Yes | The calling number. |
to | string | Yes | The number that was called. |
startTime | ISO 8601 datetime | Yes | When the call started, e.g. 2026-06-16T09:05:35.000Z. |
outgoing | boolean | No | true if your side placed the call, false if it was inbound. If omitted, VOIX infers direction from the conversation. |
duration | integer (seconds) | No | Call length in seconds. Typically sent on the finishing beat. |
teamId | UUID | Only with a workspace-wide key | Which team the call belongs to. Required when your API key is workspace-wide; ignored when it is team-scoped. |
userId | UUID | No | The team member who handled the call. If omitted, VOIX tries to identify the agent from the transcript. See Attribution. |
The body is strict: any field not listed above causes the request to be
rejected with 400. Send only these keys.
Responses
/submit returns 202 Accepted with one of two bodies, depending on whether the
recording was included:
| When | Body |
|---|---|
No recordingUrl yet (beat 1) | { "status": "received", "callId": "…" } |
recordingUrl present (beat 2) | { "status": "transcribing", "callId": "…", "jobId": "…" } |
From there the call processes on its own. Track its progress through the call lifecycle.
What you cannot set
Transcription behaviour, the spoken language, how speakers are separated, how many speakers to expect, audio handling, and timestamps, is owned by VOIX and tuned for consistent quality. There are no parameters to override it. This is deliberate: it keeps every call in your account directly comparable, rather than depending on settings a sender happened to pass. Language, for instance, is detected automatically.