curl --request POST \
--url https://api.voice.mergenlab.ai/v1/calls \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"agent_id": "agt_credfin_dpd_8_30_m",
"to": "+9198XXXXXX01",
"variables": {
"case_id": "CF-LN-208841",
"borrower_first_name": "मोहित",
"call_stage": "DPD 8-30",
"emi_amount": 4200,
"original_due_date": "2026-09-25",
"dpd": 17,
"late_charges": 374,
"total_overdue": 4574,
"max_ptp_days": 3,
"min_part_payment": 1500
},
"metadata": {
"loan_id": "CF-LN-208841",
"borrower_ref": "BR-55102"
}
}
'{
"id": "call_9f1c2a7e4b3d4c0e8a6b5d2f1e0c9b8a",
"agent_id": "agt_credfin_dpd_8_30_m",
"call_type": "ai_voice",
"to": "+9198XXXXXX01",
"status": "completed",
"scheduled_for": null,
"attempts_count": 1,
"outcome": "promise_to_pay",
"summary": "The borrower confirmed the overdue amount of INR 4,574 and promised to pay in full by Friday.",
"duration_sec": 61.5,
"billable_minutes": 2,
"cost": {
"amount_micros": 9180000,
"currency": "INR",
"status": "final"
},
"has_recording": true,
"has_transcript": true,
"metadata": {
"loan_id": "CF-LN-208841",
"borrower_ref": "BR-55102"
},
"created_at": "2026-10-12T05:30:00.120Z",
"updated_at": "2026-10-12T05:37:42.906Z",
"ended_at": "2026-10-12T05:31:14.880Z"
}Create an AI voice call or a human call
Creates a call. The body depends on call_type:
ai_voice(default whencall_typeis left out): a voice agent callsto. The agent must belong to your account and be active. Variables are the agent’s defaults merged with yours (values are sent to the agent as strings); every variable in the agent’srequired_variablesmust end up set, and the agent’s opening message must render without unresolved{{placeholders}}. The call is queued and dialled as soon as the agent’s calling window and your concurrency allow; outside the window it is accepted withscheduled_forset to the next window start. Answer:202withstatus: "queued".human: ringsagent_phoneandtoand bridges them from caller IDfrom. Checked in this order: idempotent replay, human calling enabled, human calling hours, caller ID, daily cap, one live call peragent_phone. Answer:202withstatus: "dialling",agent_id: nullandhuman.status: "initiated"(it moves on within a second; follow it withcall.status_changedwebhooks orGET /v1/calls/{id}).
call_type: "reachability" is rejected here (422); use POST /v1/reachability-checks.
curl --request POST \
--url https://api.voice.mergenlab.ai/v1/calls \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"agent_id": "agt_credfin_dpd_8_30_m",
"to": "+9198XXXXXX01",
"variables": {
"case_id": "CF-LN-208841",
"borrower_first_name": "मोहित",
"call_stage": "DPD 8-30",
"emi_amount": 4200,
"original_due_date": "2026-09-25",
"dpd": 17,
"late_charges": 374,
"total_overdue": 4574,
"max_ptp_days": 3,
"min_part_payment": 1500
},
"metadata": {
"loan_id": "CF-LN-208841",
"borrower_ref": "BR-55102"
}
}
'{
"id": "call_9f1c2a7e4b3d4c0e8a6b5d2f1e0c9b8a",
"agent_id": "agt_credfin_dpd_8_30_m",
"call_type": "ai_voice",
"to": "+9198XXXXXX01",
"status": "completed",
"scheduled_for": null,
"attempts_count": 1,
"outcome": "promise_to_pay",
"summary": "The borrower confirmed the overdue amount of INR 4,574 and promised to pay in full by Friday.",
"duration_sec": 61.5,
"billable_minutes": 2,
"cost": {
"amount_micros": 9180000,
"currency": "INR",
"status": "final"
},
"has_recording": true,
"has_transcript": true,
"metadata": {
"loan_id": "CF-LN-208841",
"borrower_ref": "BR-55102"
},
"created_at": "2026-10-12T05:30:00.120Z",
"updated_at": "2026-10-12T05:37:42.906Z",
"ended_at": "2026-10-12T05:31:14.880Z"
}Authorizations
Authorization: Bearer vg_live_<32 hex characters>. Keys are issued by Mergen admins and shown once.
Missing or invalid key: 401 unauthorized. Suspended account: 403 tenant_suspended.
Headers
1 to 64 characters, unique per logical request (a UUID works). Same key and body again: 200 with the current
resource. Same key, different body: 409 idempotency_conflict. Missing: 422 validation_error.
1 - 64Body
- AI voice call
- Human call
POST /v1/calls body, chosen by call_type: leave call_type out (or send "ai_voice") for an AI voice call,
send "human" for a human call. Exactly one of the two shapes matches any valid body.
call_type works as the discriminator, but it is not declared with the OpenAPI discriminator keyword: in
OpenAPI 3.1 a discriminator property must always be present, while this API defaults a missing call_type to
ai_voice. Generated clients may always send call_type; "ai_voice" is accepted.
An active agent of your account (GET /v1/agents).
1 - 128"agt_credfin_dpd_8_30_m"
Customer number (Indian; see "Phone numbers").
1 - 32"+9198XXXXXX01"
Optional; ai_voice is the default.
"ai_voice"Preferred caller number: one of your active numbers (GET /v1/numbers), E.164. Each call gets one of your
numbers connected for voice AI that is free at dial time (a number carries one call at a time): this one
when it is free, else the free number used least recently. When every such number is on a call, the call
waits in the queue (estimated_start_at). Leave it out to prefer the agent's default number. A number that
is not one of your active voice numbers is 422 caller_id_not_owned; an account with no number connected
for voice AI is 422 no_voice_ai_number.
1 - 32"+9180XXXXXX79"
Values for the agent's variables, merged over the agent's defaults. Names are letters, digits and
underscores (start with a letter or _, at most 64 characters). Every name in the agent's
required_variables must end up set.
Show child attributes
Show child attributes
Your own JSON object, returned unchanged (at most 4 KB as JSON). Mergen never reads it.
Earliest time to dial (ISO 8601 with Z or an offset), at most 7 days ahead. A time in the past means now.
The calling window still applies.
Response
Replay of an earlier request with the same Idempotency-Key and body. Returns the call's current state.
A call of any type. human is present only on human calls; reachability_check_id and reachability only on
reachability dials; broadcast_id and broadcast only on voice broadcast dials; campaign_id,
campaign_contact_id and campaign_step_id only on calls a campaign placed (absent, not null, on other
calls). outcome is the agent's outcome for AI calls, the terminal human.status for human calls and the
result for reachability and broadcast dials.
call_ + 32 hex characters.
"call_9f1c2a7e4b3d4c0e8a6b5d2f1e0c9b8a"
The voice agent; null for human calls, reachability dials and broadcast dials.
"agt_credfin_dpd_8_30_m"
ai_voice: a voice agent calls the customer. human: your agent and the customer bridged by phone.
reachability: one dial of a reachability check. broadcast: one dial of a voice broadcast.
ai_voice, human, reachability, broadcast Customer number, E.164.
"+9198XXXXXX01"
queued (waiting for its first dial, a scheduled time, the calling window or a retry), dialling (an attempt
is live), then terminal completed (a person was connected), no_answer, busy, failed, canceled.
An AI call goes back to queued while a retry is pending.
queued, dialling, completed, no_answer, busy, failed, canceled When a queued call will be dialled (a future schedule_at, the next calling window start, or the retry time). null when it is due now or the call is not queued.
Dial attempts made so far.
x >= 0AI calls: the outcome reported by the agent for the latest attempt (agent-specific, for example
promise_to_pay, no_commitment, callback_requested), null until analysed. Human calls: the terminal
human.status. Reachability and broadcast dials: the dial result.
"promise_to_pay"
Short summary of the conversation (AI calls), null otherwise or until analysed.
Seconds of the latest attempt: conversation length for AI calls, talk time (agent and customer bridged)
for human calls, seconds held after the answer for reachability dials, seconds from the answer to the
hangup for broadcast dials. null until known.
61.5
Billable minutes summed over the call's attempts (each connected attempt rounded up to whole minutes; 0 when not connected).
x >= 0Your cost summed over the call's attempts; pending while the call is not over or any attempt's cost is not final.
Show child attributes
Show child attributes
Always false for human calls, reachability dials and broadcast dials.
The metadata you sent (reachability dials carry the number's items_metadata, broadcast dials the broadcast's and the item's metadata), or null.
When the call reached a terminal status.
Only on AI calls, once dialled: the number the latest attempt dialled from (given at dial time from your
free numbers; see from on the request).
"+9180XXXXXX79"
When a call that is waiting for a free line is expected to start. An estimate; null once the call is placed.
Live state of a human call (human on CallView; only on human calls).
Show child attributes
Show child attributes
The check this dial belongs to (reachability dials only).
"rch_4e7b1c9d2a3f4e5b8c6d7a8b9c0d1e2f"
One dial of a reachability check (reachability on CallView; only on reachability calls). The call's
status for a ring-check dial: dialling while live, completed only when the customer picked up
(answered), no_answer for ringing (not answered) and switched_off, busy for busy, failed for
invalid and failed, canceled for canceled.
Show child attributes
Show child attributes
The voice broadcast this dial belongs to (broadcast dials only).
"vbc_7c1e9a3b5d2f4e6a8b0c2d4e6f8a1b3c"
One dial of a voice broadcast (broadcast on CallView; only on broadcast calls). The call's status:
dialling while live, completed for played and partial (a person heard the message; priced),
no_answer for voicemail and no_answer, busy, failed for failed and invalid, canceled.
Show child attributes
Show child attributes
Human calls only (absent on others); null until your agent sets one (PUT /v1/calls/{id}/disposition).
Show child attributes
Show child attributes
The campaign that placed this call (campaign calls only; GET /v1/calls?campaign_id=).
"cmp_3b9e1f7a2c4d4e6f8a0b1c2d3e4f5a6b"
The campaign record (rec_...) the call was for (campaign calls only).
"rec_1a2b3c4d5e6f40718293a4b5c6d7e8f9"
Which attempt of the record's ladder the call is, as attempt_<number> (campaign calls only).
"attempt_2"