Calls
Use call tasks to turn a structured workflow step into one or more real phone interactions.
Use the Calls API Reference for the exact HTTP request and response schemas. See the error handling guide for retry behavior and the terminal webhooks guide for asynchronous completion.
Call inputs
task is the natural-language instruction for the call task. Keep it specific and outcome-oriented.
recipients is optional. When it is omitted, include the phone target in task and CALL-E will infer it. Use recipients for explicit batch targets; each recipient contains a phones array of E.164 numbers.
Check the supported regions and languages
before choosing a recipient's region and locale. A valid E.164 number does
not establish that its destination is supported.
Examples use phone placeholders such as <E164_PHONE> and <RECIPIENT_1_E164_PHONE>. Replace them with phone numbers you own or are authorized to call.
result_schema is a JSON Schema object for the whole call task. CALL-E validates the structured result against it before returning the terminal call task state. Object schemas are strict by default, so fields not declared in properties are rejected.
recipient_result_schema is an optional JSON Schema object for each recipient result. It uses the same strict object behavior.
metadata is copied through to the call task and webhook payload. Use it for workflow identifiers, user ids, or reconciliation fields.
webhook_url is an optional request-level endpoint for terminal webhooks.
The server SDKs also reserve a context input for future SDK-side workflow data. It is not sent to the API yet.
Direct HTTP with curl
Set your API key, then create a call with a stable idempotency key. Replace
<E164_PHONE> with a phone number you own or are authorized to call.
Code
The response contains the call task id. Use it to read the current state or
the ordered lifecycle events:
Code
Call identifiers
- Calls API
call_id: use the top-levelid(call_...) in HTTP and Python, orcall.idin TypeScript. - Dashboard Call Record ID: use
recipients[].attempts[].provider_call_idin HTTP and Python, orcall.recipients[i].attempts[j].providerCallIdin TypeScript.
Use call_id with GET /v1/calls/{call_id} and
GET /v1/calls/{call_id}/events. Do not use provider_call_id as call_id;
it identifies one attempt and may be null.
Event-list items expose the CallTask ID as call_id. Terminal webhooks expose
it as data.id; the webhook's top-level id identifies the event.
Persist the returned Call ID with your workflow record. The Calls API does not
provide a list endpoint: GET /v1/calls cannot recover IDs you did not save.
See Recover after a restart or lost response.
TypeScript:
Code
Python:
Code
Structured results
Structured results let you turn the terminal call evidence into a stable JSON object for your workflow. The schema is an extraction contract: the SDK sends the schema to CALL-E, CALL-E extracts a result from the completed call evidence, and the service validates the result before returning it.
The extraction model uses the call transcript, ASR, and Calling facts as primary evidence. It uses the post-call summary and outcome as supporting context. If CALL-E cannot produce a schema-valid result from the evidence, the public structured_result is null.
Use result_schema for one result object that describes the whole call task. Use recipient_result_schema when each recipient needs an independent result, especially for batch calls. TypeScript uses resultSchema and recipientResultSchema; Python uses result_schema and recipient_result_schema. The JSON Schema object itself is the same shape.
For recipient_result_schema, avoid reserved recipient response field names such as summary, status, transcript, call_id, and timing fields. Use custom names such as customer_summary, notes, or reason instead.
Descriptions are passed to the extraction model. Use description to explain what each field means and how enum values should be selected. Descriptions guide extraction, but they are not hard validation rules. Hard validation comes from type, required, enum, and additionalProperties.
Supported schema features:
type:object,string,number,integer,boolean, orarraypropertiesrequiredenum- nested
objectfields - simple
array.items descriptionadditionalProperties: false
Unsupported schema features include $ref, oneOf, anyOf, allOf, recursive schemas, complex format validation, and additionalProperties: true.
For business decisions, prefer string enums over booleans when the answer can be unclear. Include an unknown value when the call may not provide enough evidence.
Code
When a result drives automation, add an evidence field so your system can inspect why CALL-E made the classification.
Classify the final endpoint
The Calls API does not return a built-in AMD disposition or answered_by field. Define the classification with a per-recipient Structured Result. You control the property name and enum values.
Code
Read call.recipients[i].structuredResult in TypeScript, call["recipients"][i]["structured_result"] in Python, or recipients[i].structured_result over HTTP. CALL-E returns null when it cannot produce a schema-valid recipient result or when the request omits recipient_result_schema. The example uses unknown as a schema-valid fallback.
Sales handoff
Use this pattern when a prospect should be routed to a human if they ask for help or show strong interest.
Code
Appointment confirmation
Use this pattern when calling a business to confirm, reschedule, or cancel an appointment.
Code
Batch recipient result
Use recipientResultSchema when each recipient should have their own answer.
Code
Support triage
Use this pattern when a call should determine whether an issue was resolved or needs follow-up.
Code
Pricing or quote request
Use this pattern when a prospect may ask about pricing, quotes, discounts, or budget.
Code
Best practices
- Keep schemas focused. A small schema with clear fields is more reliable than a large schema with many optional fields.
- Put enum selection rules in the field
description. - Include
unknownwhen the call may not contain enough evidence. - Use
requiredfor fields your workflow always expects. - Use
additionalProperties: falseto prevent extra fields from being returned. - Add an evidence or summary field when the result triggers workflow automation.
- Do not rely on
descriptionfor validation. Use schema constraints for enforceable behavior.
Call status
The call task's status has exactly five values:
| Status | Terminal? | Meaning |
|---|---|---|
queued | No | The call task is queued. |
in_progress | No | The call task is running, including post-call finalization. |
completed | Yes | The call task completed. Check its results for the business outcome. |
failed | Yes | The call task failed. Keep the failure fields as diagnostic context. |
canceled | Yes | The call task was canceled. |
no_answer, busy, and voicemail are not Calls API lifecycle statuses.
Recipient and attempt objects have their own status enums; do not substitute
them for the top-level call status. A completed state does not establish
that a person answered or that your business objective succeeded. See
Task completion for interpreting the business result.
Parallel and quorum-based dispatch
The Calls API does not expose an operation for clients to cancel a call after
it has been created. A call that is already in flight may therefore continue
to completion even when your application no longer needs its result. The
canceled resource status does not imply that clients can request
cancellation.
For workflows that need only a target number of confirmations, dispatch calls in controlled waves instead of starting every call at once. Count terminal results through polling or webhooks, and stop creating subsequent waves after the confirmation target is reached. Choose a wave size that balances response speed against the number of calls that may still be in flight when the target is met.
Idempotency
Pass an idempotency key when a workflow step might retry. The key maps to the Idempotency-Key HTTP header and prevents duplicate call creation for the same external operation.
Use a stable workflow key, not a random UUID generated at each retry.
Recover after a restart or lost response
Save the idempotency key and original request with your workflow record before
sending POST /v1/calls. Save the returned Call ID as soon as the response
arrives. Keep that record across application restarts.
| What you saved | Recovery action |
|---|---|
| Call ID | Read GET /v1/calls/{call_id} or resume SDK polling with that ID. Do not create another call to learn the existing call's outcome. |
| Original request and idempotency key, but no Call ID | Repeat the create request with the same key and unchanged body. The documented idempotency contract returns the original call instead of creating a duplicate. Save its ID. |
| Neither the Call ID nor the original request and key | Reconcile the original operation before submitting a replacement. A lost response does not prove that the first request was rejected. |
For an idempotent replay, preserve the entire request, including metadata,
schemas, and webhook_url. Rebuilding it with a new timestamp or other changed
value can produce idempotency_conflict. Check the saved request if this occurs;
do not generate a new key just to bypass the conflict.
A retry that recovers an existing operation and an intentionally new call are
different actions. Use a new key only for an intentionally new operation after
resolving the prior one. Keep local workflow identifiers in metadata for
correlation; they do not replace the Idempotency-Key header.
Task completion
task_completed is CALL-E's post-call judgment of whether the task reached
a clear end state for the user. completion_confidence is confidence in that
judgment, and evidence supports it. These fields do not require a custom
result schema.
Read execution, task completion, and the business answer separately:
| Field | Question it answers | How to use it |
|---|---|---|
status | Has the call task finished executing? | Use the lifecycle states to decide whether to keep waiting. completed alone does not establish task or business success. |
task_completed | Did CALL-E judge that the requested task reached a clear end state? | Read it with completion_confidence and evidence. Confidence applies to this judgment, not to the likelihood of a favorable business answer. |
structured_result | What business answer was extracted? | Check the fields defined by your result schema and the supporting transcript before taking a business action. |
A true value or high confidence does not establish that a person answered
or that your business objective was met. Check the business answer in
structured_result against the call transcript. Use the
custom answered_by example to extract an
endpoint classification alongside your business result. Keep unknown
answers unresolved.
Example: an answered question with an unfavorable result
Suppose the task is: "Ask whether a table for two is available at 7 p.m.
Do not make a reservation." The restaurant says no tables are available.
With a caller-defined table_available result field, an illustrative terminal
response excerpt is:
Code
The availability question reached a clear answer, even though the answer was
unfavorable. The application should report "No table available", not
"Reservation successful". If the requested task were to make a reservation,
the application would need evidence of a confirmed booking; this example does
not establish that outcome. A null result or an unknown answer must remain
unresolved rather than becoming a yes or no from status alone.
Polling and events
Use waitForResult or wait_for_result for simple server-side polling. Use events when you need a developer-facing trace of the call lifecycle.
Before mapping a failed call to no answer or decline, read
Accepted call execution outcomes.
Calls API failure_code values are not a published enum, and Goal Run error
codes do not define the Calls API contract.
When the terminal structured_result is null, CALL-E did not produce a schema-valid whole-task result from the available evidence. Recipient-level structured results use the same rule: invalid or unsupported values are returned as null.
Each recipient attempt can include transcript_turns, an ordered list of structured transcript turns for that dial attempt. Each turn has offset_seconds, speaker, and text; speaker is bot, user, or unknown. The array is empty when no transcript is available.
TypeScript:
Code
Python:
Code