Skip to content

Call Metadata API

Call center reporting needs facts that are not in the audio: when the call happened, which agent handled it, whether it was inbound or outbound. There are three ways to provide them:

  • Per file at upload, as extra fields on POST /api/files/ — best when your system uploads recordings one by one
  • Per file afterwards, with PATCH /api/files/{id}/ — for corrections and for metadata that arrives after the recording
  • Per project, as a CSV manifest on POST /api/projects/{id}/call-manifest/ — best for bulk loads and for backfilling metadata after the fact

All three write to the same place, so you can mix them; the last write wins. Metadata sent through the API always takes precedence over the agent name the AI extracts from the conversation.

Whatever a call currently carries is readable on the file resource as call_metadata.

All endpoints require either a session cookie or an API key — see Authentication.


The file upload endpoint accepts optional call metadata alongside the regular fields (see Transcription API for the base request).

Content-Type: multipart/form-data

Additional form fields:

FieldTypeDescription
call_datetimedatetimeWhen the call took place (ISO 8601, e.g. 2026-06-15T09:12:00Z)
agent_idstring (≤64)The agent’s identifier in your own systems
agent_namestring (≤255)The agent’s display name
directionstringinbound or outbound
caller_numberstring (≤64)Customer’s phone number
campaignstring (≤255)Campaign or queue name

Fields left out are simply not set. Blank values are ignored here, so an empty field never shadows a manifest row that is already waiting for this file.

Example:

Terminal window
curl -X POST https://app.uspeech.io/api/files/ \
-H "Authorization: Api-Key $USPEECH_KEY" \
-F "project=312" \
-F "file_type=audio" \
-F "file=@./call_001.mp3" \
-F "call_datetime=2026-06-15T09:12:00Z" \
-F "agent_id=A-06" \
-F "agent_name=Ana Diaz" \
-F "direction=inbound" \
-F "caller_number=+34600111222" \
-F "campaign=Retention"

Every file resource — from POST /api/files/, GET /api/files/{id}/ and GET /api/files/?project={id}/ — includes a call_metadata object. It is null for files that have no call record, which is every file in a project that is not a call project.

{
"id": 9871,
"original_filename": "call_001.mp3",
"status": "transcribed",
"call_metadata": {
"call_datetime": "2026-06-15T09:12:00Z",
"call_datetime_source": "api",
"agent_id": "A-06",
"agent_name": "Ana Diaz",
"agent_source": "api",
"direction": "inbound",
"caller_number": "+34600111222",
"campaign": "Retention"
}
}

The two _source fields tell you where the value came from, which is useful when reconciling with your own system:

FieldValuesMeaning
call_datetime_sourceapi, manifest, upload_timeupload_time means no real call time was ever provided — the file’s upload time is standing in
agent_sourceapi, manifest, llm, ""llm means the agent name was extracted from the conversation, not supplied by you; "" means no agent is linked

Update the call metadata of a file that is already uploaded. Only the fields you send are touched, so you can change one value without restating the rest.

Content-Type: application/json (or multipart/form-data)

Body fields: the same six as the upload endpoint.

Clearing a value: send an empty string. {"campaign": ""} removes the campaign; sending agent_id and agent_name both empty unlinks the agent. This differs from the CSV manifest, where blank cells are skipped rather than treated as an instruction to clear.

call_datetime is the exception — it cannot be cleared, because a call always needs a time. Send a new value to change it, or omit it to leave it alone; null is rejected with 400. Clearing it in the product UI restores the file’s upload time.

Updating metadata does not re-run analysis. Scores, topics, sentiment and rubric results are left untouched.

Response (200 OK): the updated file resource, including the new call_metadata.

Errors:

StatusWhen
400The project is not a call project, the file is not a recording or transcript (only audio, srt and vtt carry call metadata), or a value is invalid (e.g. call_datetime: null, an unknown direction)
404The file does not exist or is not visible to the caller

Example — change the campaign and clear the direction:

Terminal window
curl -X PATCH https://app.uspeech.io/api/files/9871/ \
-H "Authorization: Api-Key $USPEECH_KEY" \
-H "Content-Type: application/json" \
-d '{"campaign": "Winback", "direction": ""}'

Upload a CSV manifest with metadata for many calls at once. Rows are matched to the project’s files by filename, and rows that don’t match anything yet are stored on the project and applied to files uploaded later.

{id} is the project’s numeric ID — see Projects if you need to look it up.

Auth: API key or session.

Content-Type: multipart/form-data

Form fields:

FieldRequiredDescription
fileyesThe CSV manifest

CSV columns (header row required): filename and call_datetime are required; agent_id, agent_name, direction, caller_number, campaign are optional.

filename,call_datetime,agent_id,agent_name,direction,caller_number,campaign
call_001.mp3,2026-06-15 09:12:00,A-06,Ana Diaz,inbound,+34600111222,Retention
call_002.mp3,2026-06-15 09:41:00,A-10,Luis Gomez,outbound,+34600333444,Winback

Accepted date/time formats: ISO 8601, YYYY-MM-DD HH:MM[:SS], and DD/MM/YYYY HH:MM[:SS]. Values without a time zone are read in the server’s time zone.

Matching: exact filename first, then the name without its extension (case-insensitive), so call_001.wav in the manifest matches an uploaded call_001.mp3. Audio files and transcript uploads (SRT/VTT) are both matched.

Response (200 OK):

{
"matched": 118,
"unmatched": ["call_119.mp3", "call_120.mp3"],
"errors": ["Row 42 (call_041.mp3): invalid call_datetime '15-06-2026'"]
}
  • matched — rows applied to a file that already exists
  • unmatched — rows kept for files that have not been uploaded yet
  • errors — rows that were skipped, with the reason

Errors:

StatusWhen
400The project is not a call project, no file was sent, or the CSV had no valid rows (the response includes errors)
404The project does not exist or is not visible to the caller

Example:

Terminal window
curl -X POST https://app.uspeech.io/api/projects/312/call-manifest/ \
-H "Authorization: Api-Key $USPEECH_KEY" \
-F "file=@./calls_june.csv"

Once the calls have been analyzed, the metadata you attached here becomes the grouping and filtering dimensions of the report — by agent, direction, campaign and call date. See the Call Reports API for reading those results back.