POST /v1/calls sends one finished call. Chambr saves it, finds the rep's
side of the conversation and queues it for scoring.
Request fields
{
"external_id": "00T5f00000ABCdE",
"provider": "salesforce",
"occurred_at": "2026-09-28T15:02:14Z",
"call_type": "discovery",
"scorecard_id": null,
"rep": { "email": "sarah.reid@yourcompany.com", "name": "Sarah Reid" },
"participants": [
{ "role": "rep", "name": "Sarah Reid", "email": "sarah.reid@yourcompany.com" },
{ "role": "customer", "name": "Dana Whitfield", "company": "Acme Freight" }
],
"transcript": {
"segments": [
{ "speaker": "Dana Whitfield", "text": "Morning. I have about twenty minutes.", "start_ms": 0 },
{ "speaker": "Sarah Reid", "text": "Understood, I will keep it tight.", "start_ms": 4100 }
]
},
"metadata": { "salesforce": { "task_id": "00T5f00000ABCdE", "opportunity_id": "0065f00000XyZ" } }
}
| Field | Required | Notes |
|---|---|---|
external_id |
yes | Your stable id for the call, such as the Salesforce Task id. 1 to 200 characters. |
provider |
yes | Where the call comes from: letters, digits, - and _, up to 32 characters. Chambr lower-cases it. (provider, external_id) is the idempotency key. |
occurred_at |
yes | RFC 3339 with Z or a colon offset (+00:00, -05:30). +0000 without a colon is rejected. Between 2000-01-01 and one day from now. |
rep |
no | Who the call is scored for. See Identify the rep and Send a call without a rep. |
rep.email |
when rep is sent |
The rep's Chambr login email. |
rep.name |
no | Helps match the rep's speaker label. |
transcript |
yes | Exactly one of segments or text, plus optional rep_speaker. See Transcript formats. |
call_type |
no, recommended | discovery, cold_call, warm_call, customer_success, cross_selling, evaluation, negotiation, gatekeeper or inbound_call. |
scorecard_id |
no | A published scorecard of the rep's team. |
participants |
no | Up to 50, each with role (rep, customer or other), name, and optional email, company and speaker_label. The first customer becomes the call's title in Chambr. |
recording_id |
no | From Attach a recording. |
metadata |
no | Any JSON object for your reference, up to 16 KB and 5 levels deep. Stored with the call, never used for scoring. Send only the personal data you need. |
Optional fields may be omitted or null. Text must not contain the NUL
character. Chambr rejects any other field with 422 unknown_field; put custom
data in metadata.
| Limit | Value |
|---|---|
| Request body | 1 MiB (413 payload_too_large) |
| Transcript | 2,000 turns after merging consecutive turns by one speaker, and 400,000 characters (422 transcript_too_long, never truncated) |
segments |
10,000 segments of up to 20,000 characters |
text |
600,000 characters |
participants |
50 |
Identify the rep
rep.email must be the rep's Chambr login email. The rep must be active, have
signed in once, and belong to exactly one team. Otherwise Chambr returns
422 rep_* and saves nothing. Invite the rep in Chambr, or leave rep out.
Chambr scores only the rep's side and never assumes the first speaker is the rep. It finds the rep's speaker label in this order, ignoring case and extra spaces:
transcript.rep_speaker, if sent. It must match one speaker label.- The one label that matches
rep.email,rep.name, the rep's name in Chambr, or the name, email orspeaker_labelof arole: "rep"participant. - Inference from the dialogue. It never picks a
customerorotherparticipant.
If none decides, Chambr returns 422 rep_speaker_undetermined (send
rep_speaker) or 503 inference_unavailable (retry after Retry-After).
Every other speaker counts as the customer side. attribution.speaker_source
says which rule applied.
Send a call without a rep
Leave rep out when your system does not know the Chambr user. Chambr files
the call under the API key's team, owned by the admin who created the key,
until a manager reassigns it in Chambr. attribution.rep_source is
api_key_owner. If the key's team was deleted, Chambr returns
422 team_not_configured.
{
"external_id": "00T5f00000ABCdF",
"provider": "salesforce",
"occurred_at": "2026-09-28T16:10:00Z",
"call_type": "discovery",
"participants": [
{ "role": "rep", "name": "Sarah Reid" },
{ "role": "customer", "name": "Dana Whitfield", "company": "Acme Freight" }
],
"transcript": {
"segments": [
{ "speaker": "Dana Whitfield", "text": "Thanks for calling back." },
{ "speaker": "Sarah Reid", "text": "Of course. Did the lane numbers come through?" }
]
}
}
Transcript formats
segments (preferred) is an ordered array of
{ "speaker": "...", "text": "...", "start_ms": 1234 }; start_ms is
optional. text is a plain transcript with a speaker label on each turn:
Sarah Reid: Thanks for making the time.
Dana Whitfield: Of course.
[00:12] Sarah Reid
Thanks for making the time.
00:15 - Dana Whitfield
Of course.
A transcript without speaker labels returns 422 transcript_unlabeled.
Scorecard and call type
| Field | If you omit it |
|---|---|
call_type |
Chambr classifies the call from the transcript, which slows the request, and falls back to discovery. |
scorecard_id |
The team's scorecard rule for the call type decides, else the team default. With neither, Chambr returns 422 scorecard_not_configured. If the rule or default points to a scorecard that is no longer available, 422 scorecard_rule_unavailable. |
Check status
Scoring is asynchronous and takes minutes. Poll GET /v1/calls/{id} at most
once a minute. It works for any call in your account.
status |
Meaning | What to do |
|---|---|---|
queued |
Waiting to be scored | Nothing |
scoring |
Being scored | Nothing |
scored |
Done | Open app_url |
skipped |
Not scored; skip_reason is too_short, no_scorecard, empty_scorecard or all_criteria_na |
Fix the scorecard, or nothing for a short call |
failed |
Scoring did not finish | Nothing; a manager can re-run it in Chambr |
app_url needs a Chambr login with access to the
rep's team. Store it on your record, for example the Salesforce Task.