Upload Recording
Upload an audio file to create a new recording and start transcription.
https://api.identitycall.ai/api/v1/public/recordingsUpload an audio file for transcription and analysis.
Request Body
Body Parameters (multipart/form-data)
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
file | file | Yes | - | Audio file (MP3, WAV, M4A, OGG, FLAC, WebM) |
language | string | No | en | Language code (en, es, fr, de, etc.) |
name | string | No | - | Display name for the recording |
tags[] | string[] | No | - | Tag names to attach. Matched case-insensitively against the recording's project and created there if missing. Blank entries are ignored. |
operator_id | integer | No | - | Id of the operator (agent) who handled the call. Get ids from GET /operators. An id outside your account is rejected with 422. |
Tagging on upload
Pass tags[] once per tag. Names are resolved inside the recording’s own project, so you never need to look up ids first — an unknown name simply becomes a new tag in that project:
curl -X POST "https://api.identitycall.ai/api/v1/public/recordings" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY" \
-F "file=@call.mp3" \
-F "project_id=12" \
-F "tags[]=vip" \
-F "tags[]=callback-requested"The attached tags come back in the response under data.tags. Because names create tags on first use, a typo becomes a real tag in that project — see Tags if you would rather pre-define the vocabulary with POST /tags and treat unknown names as a bug in your integration.
Tags are project-scoped. vip in project 12 and vip in project 13 are separate tags with separate ids.
The parameter is tags, plural — and it must be sent as tags[].
Sending singular tag is rejected with a 422 naming the correct parameter, so the mistake cannot pass silently.
The subtler trap is the bracket. Most HTTP clients encode a list under a plain tags key as repeated fields, and only the last value survives:
| Sent on the wire | What the API receives |
|---|---|
tags=a&tags=b | "b" — the first value is lost |
tags[]=a&tags[]=b | ["a", "b"] |
With one tag both forms happen to work, which is why this surfaces only once you send a second tag. In Python requests, use the bracketed key:
data = {"project_id": 12, "tags[]": ["vip", "callback-requested"]}
requests.post(url, headers=headers, files={"file": (name, blob, "audio/wav")}, data=data)Attributing the call to an operator
If your telephony platform already knows which agent took the call, send that
agent’s operator_id and IdentityCall will credit them instead of trying to work
it out from the audio.
Operator ids are numeric and account-wide — unlike tags, they are not created by name on first use. The usual integration shape is: fetch the roster once, map your own agent identifiers to IdentityCall ids, and create anything missing.
# 1. List the operators you already have
curl "https://api.identitycall.ai/api/v1/public/operators" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY"
# 2. Create one that does not exist yet (phone_number is required and unique)
curl -X POST "https://api.identitycall.ai/api/v1/public/operators" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Jonas Jonaitis", "phone_number": "+37060000001"}'
# 3. Upload the recording with that operator's id
curl -X POST "https://api.identitycall.ai/api/v1/public/recordings" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY" \
-F "file=@call.mp3" \
-F "project_id=12" \
-F "operator_id=42"The assignment comes back under data.operator, including a source field:
source | Meaning |
|---|---|
api | You sent operator_id |
voice / routing | IdentityCall inferred it from voice or the dialled line |
review / manual | A person set it in the IdentityCall UI |
An api assignment wins. Voice identification and line-based routing will
not overwrite an operator you supplied, so your telephony records stay the
source of truth. A person can still correct it in the UI.
The parameter is operator_id, not operator. Sending operator is rejected
with a 422 naming the correct one, and an operator_id belonging to another
account is rejected rather than ignored — a recording is never created with
attribution silently dropped.
Request
cURL
curl -X POST "https://api.identitycall.ai/api/v1/public/recordings" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY" \
-F "file=@call-recording.mp3" \
-F "language=en" \
-F "name=Sales Call - John Smith"Response
{
"data": {
"public_id": "018f3a00-0000-7000-8000-0000000000a5",
"status": "pending",
"created_at": "2025-01-15T14:22:00Z"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
id | integer | Unique recording ID |
status | string | Initial status (always “pending”) |
created_at | string | ISO 8601 timestamp |
Transcription is asynchronous. Poll the Get Recording endpoint to check when processing is complete.
Supported Audio Formats
| Format | Extension | Max Size |
|---|---|---|
| MP3 | .mp3 | 100 MB |
| WAV | .wav | 500 MB |
| M4A | .m4a | 100 MB |
| OGG | .ogg | 100 MB |
| FLAC | .flac | 500 MB |
| WebM | .webm | 100 MB |
Supported Languages
IdentityCall supports 100+ languages via Google Gemini. Common language codes:
| Code | Language | Code | Language |
|---|---|---|---|
| en | English | ja | Japanese |
| es | Spanish | ko | Korean |
| fr | French | zh | Chinese |
| de | German | ar | Arabic |
| it | Italian | hi | Hindi |
| pt | Portuguese | ru | Russian |
| nl | Dutch | tr | Turkish |
| pl | Polish | vi | Vietnamese |
See the Introduction for a complete list.
Errors
| Status | Error | Description |
|---|---|---|
| 400 | “file is required” | No file was uploaded |
| 422 | “Invalid file type” | Unsupported audio format |
| 422 | “File too large” | File exceeds size limit |
| 422 | Unknown parameter "tag". Did you mean "tags"? | The parameter is tags, plural. The upload is rejected rather than stored untagged. |
| 422 | Unknown parameter "operator". Did you mean "operator_id"? | The parameter is operator_id. |
| 422 | operator_id N was not found in this account | The id does not exist or belongs to another account. List valid ids with GET /operators. |