Place a call
Place one outbound call now, or schedule it for later.
Place one outbound call now, or schedule it for later.
The response always carries execution_id — the id the call runs under
for its entire lifetime, minted here BEFORE anything can fail. That is what
makes an unconfirmed dial safe: if the dial is not confirmed before this
request returns, the call may already be live, and a client that redials
would ring the customer twice. Poll GET /v2/calls/{execution_id} instead; the
id is already yours.
The same id is sent in the X-Execution-Id response header — on every 201
and 202, and on any error raised once the request has been authenticated,
authorized and its body parsed (an unusable phone number, an unknown agent,
an empty wallet, no free line, a refused dial) — so even a failed request
names the call it was about. A 401, 403, 422 or request-rate 429 is answered
before any id exists and carries none.
Immediate (no scheduled_at) — 201, status: "queued". The dial is
wrapped in your organization's concurrency gate, so a burst of requests
queues against your line limit rather than overrunning it.
Queued for a line — 202, status: "scheduled", reason: "waiting_for_a_free_line". When every line your organization may use is
busy, or the call cannot be placed at that moment, an
immediate call is not refused: it is armed under the id you were given and
placed automatically, within the agent's calling hours. scheduled_at is
when it will next be tried; a call waiting for a line is dialled the moment
one frees, which can be sooner. Do not resend it. Only if the call cannot
be queued at all do you get the old answer — a 429 naming the limit with
Retry-After: 5 (busy lines), or a 503/504 (calling is temporarily
unavailable).
Outside the agent's calling window — 202, status: "scheduled",
deferred_by_calling_guard: true. An immediate call the agent may not
place right now is booked for a time inside its next open window instead of
being refused; scheduled_at says when, and calling_window names the
hours. A scheduled_at you send that falls outside the window is moved
the same way.
Scheduled (scheduled_at set) — 202, status: "scheduled". The
call is stored durably and armed: it is placed at its time even if the
platform restarts in between. Cancel it
any time before it dials with POST /v2/calls/{execution_id}/stop. It is
listed in GET /v2/calls from this moment, not from the moment it rings,
so a call waiting for its window is visible in the call history like any
other. Until it dials it reads status: "scheduled"; if its window has
closed when it comes due it stays scheduled with a new scheduled_at.
Unconfirmed — 202, status: "queued", dispatch: "pending_confirmation". The dial was sent but its confirmation did not
come back in time. The call may or may not be live.
Poll; do not redial.
402 — error 1400: your organization's credit balance cannot fund the
call. An immediate call is refused by the credit check made as it dials,
and a scheduled_at request is refused before anything is booked. The
message wording differs between the two; branch on the code.
409 — error 1205: the number is on your do-not-call list. Nothing is dialled,
queued or booked. Error 1202: the agent is switched off, so it takes no new calls;
error 1203: the agent was deleted. Nothing is dialled, queued or booked.
Switch the agent on and send the request again. Error 1204: a workflow's
"Before a call is placed" holds this agent's calls, and the number has had
its calls for now, and the call could not be queued. Nothing is dialled;
Retry-After (seconds) and the message say when it can be called again.
Held by the call limit — 202, status: "scheduled", reason: "held_by_call_limit". A workflow's "Before a call is placed" holds this
agent's calls and the number has had its calls for now: the call is queued
under the id you were given and placed automatically at scheduled_at,
when the person can be called again. A call sent with scheduled_at is
held the same way when its time comes.
variables fills the {tokens} in your agent's prompt and welcome
message. metadata is merged over it, so a key in both takes the
metadata value. The merged object is what GET /v2/calls/{id} returns
as variables from the moment this response is sent.
Starting language — variables.agent_language starts the call in one of
an agent's languages: its code, such as "ta"; case does not matter. On an
agent with two or more languages, a code it doesn't have is a 400 (error
1000) whose message lists the agent's languages, and nothing is dialled,
queued or booked. Leave it out, or empty, to start in the agent's default
language. On an agent with one language it is an ordinary variable.
Rate limit: 1200 requests per minute per organization, shared by the endpoints that place, stop and transfer calls and create campaigns. Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.
v2/callsAuthorization
AuthorizationRequiredBearer <token>
Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.
In: header
Request Body
application/jsonRequiredagent_idRequiredAgent Id
The agent that will conduct the call. Must belong to your organization. If it carries a calling window, that window decides when this call may ring — see scheduled_at.
1to_numberRequiredTo Number
Recipient in E.164 format, e.g. +919812345678 (7-15 digits).
1from_numberFrom Number | null
Caller ID in E.164 format. Omit to have Graine pick one of the numbers registered to your organization.
variablesVariables
Prompt variables. Every {token} in the agent's prompt and welcome message is filled from here.
metadataMetadata
Additional context merged OVER 'variables' — on a key present in both, the value here wins.
scheduled_atScheduled At | null
ISO-8601 timestamp WITH a UTC offset (+05:30, -08:00, or Z). Must be at least 2 minutes and at most 30 days ahead. Omit to place the call immediately.
If the agent carries a calling window, a time outside it is NOT refused — the call is moved to a time INSIDE the next open window, and the 202 reports that time in scheduled_at with deferred_by_calling_guard: true. So this field is a request, and the response is the answer. The same applies when you omit it: an immediate call outside the window is scheduled rather than dialled.
The time is spread across the window, not stacked on its opening minute: ten calls held overnight against 09:00-21:00 land at ten different times through the day. It is derived from the execution id, so it is stable — re-reading the call returns the same time, and it never falls before the window opens or in its last five minutes.
recordRecord
Record the call audio. Applies to a scheduled call too — it is stored with the call and used at the moment it dials.
truetimeout_secondsTimeout Seconds
How long to let the recipient's phone ring before giving up. Applies to a scheduled call too.
30Minimum: 5Maximum: 120Query Parameters
organization_idOrganization Id
Optional. Must equal your key's organization.
Response Body
201
Call accepted and being placed.
execution_idRequiredExecution Id
Track the call with this id for its whole life.
statusRequiredStatus
Always "queued".
call_sidCall Sid | null
Provider-side leg id, for support tickets only.
agent_idRequiredAgent Id
The agent conducting the call.
to_numberRequiredTo Number
Recipient dialled.
from_numberFrom Number | null
Caller ID used.
created_atCreated At | null
When the call was accepted.
202
Either the call is scheduled for later (status "scheduled", with the time it will ring — this includes an immediate call that was queued because no line was free, which also carries reason "waiting_for_a_free_line"), or the dial was accepted and not confirmed in time (status "queued", dispatch "pending_confirmation"). Never redial on this status — the execution_id is already yours; poll it.
responseRequiredResponse 202 Create Call V2 Calls Post
400
1000 — malformed or contradictory input. 1002 — a required parameter is missing.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
401
1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented instead of an API key.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
402
1400 — your credit balance cannot fund this call. Top up and retry.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
403
1102 — the key is valid but lacks the scope this endpoint requires, or names another organization. GET /v2/scopes reports what a key holds.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
404
1200 — no such resource in your organization. A resource belonging to another organization answers 404, never 403.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
409
1202 — the agent is switched off, so it takes no new calls: switch it on and try again. 1203 — the agent was deleted, so it takes no new calls.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
422
1001 — the body or query failed validation; the message names the first offending field.
errorRequiredinteger
Stable integer code from the error table. Branch on this, not on the message.
messageRequiredstring
One human-readable sentence. Wording may change; the code will not.
429
1300 — the per-organization request rate or concurrent-call limit was reached. Carries Retry-After.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
503
1501 — a service this endpoint depends on is unreachable or returned a 5xx.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
504
1502 — a service this endpoint depends on did not answer in time.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
Call accepted and being placed.

