Calls
Start outbound voice calls with explicit service routing, startup instructions, retry correlation, and best-effort patient lineage.
The outbound call endpoint lets you place a voice call from a workspace phone number to a patient. The request validates a patient entity and includes a reason; after the voice service accepts the call, the Platform API makes a best-effort attempt to emit lineage metadata on that entity.
The request requires a workspace API key, phone_to, use_case_id, service_id, reason, exactly one patient identifier, and a valid outbound voice setup. No trigger or campaign resource is required for an on-demand call.
Quick Start
curl -X POST https://api.platform.amigo.ai/v1/{workspace_id}/calls/outbound \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_to": "+18005551234",
"use_case_id": "cccccccc-0000-0000-0000-000000000001",
"service_id": "dddddddd-0000-0000-0000-000000000001",
"patient_entity_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"reason": "lab_results"
}'The response includes a call_sid for tracking. When the best-effort lineage emit succeeds, event_id points to that world event; otherwise it is null:
{
"call_sid": "CA1234567890abcdef",
"status": "queued",
"phone_from": "+12125559876",
"setup_id": null,
"event_id": "f9e8d7c6-b5a4-3210-fedc-ba0987654321"
}Endpoint
Initiate an outbound voice call from a workspace phone number. channel-manager selects the optimal number for the given use_case_id. Supports idempotency via the idempotency_key field.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Request body for creating an outbound call.
use_case_id is required: channel-manager selects the optimal outbound
phone number bound to that use case (the sole caller-ID resolution path).
Destination phone number in E.164 format.
Channel-manager use case ID. channel-manager selects the optimal outbound phone number bound to this use case.
Patient entity UUID in the world model. Must exist in workspace as a person entity. Provide either patient_entity_id or patient_canonical_id.
Patient world model canonical_id of the form 'source:resource_type:id' (e.g. 'charmhealth:Patient:67890'). The structural regex on CanonicalIdString rejects spaces, names, DOBs, and similar regulated content so PHI cannot leak into audit events or pipeline projections. The raw value is deliberately not recorded in the outbound.initiated event — correlation back to the source system is via the resolved entity_id joined to world.entities_synced.canonical_id. Resolved against the SDP-projected world.entities_synced table; an entity created moments ago may not yet be visible if the projection is lagging. Provide either patient_entity_id or patient_canonical_id, not both.
^[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+$Why the call is being made (e.g. appointment_reminder, follow_up, lab_results).
Service ID for the voice agent to use.
Optional system prompt override for this call.
What the call should accomplish. Injected into agent context.
Classification tags for analytics.
Prior call_sid if this is a callback from a previous call.
Client-provided idempotency key. Auto-generated if omitted.
World model outbound_task entity ID for completion feedback.
Successful Response
Response from creating an outbound call.
Twilio call SID for the outbound call
Initial call status (typically 'queued')
Resolved caller ID when use_case_id was used.
Channel-manager setup ID when use_case_id was used.
World event ID for the outbound.initiated event.
Invalid phone number format
No phone number available for use case
Validation Error
Rate limit exceeded
Upstream Twilio or voice agent error
Voice agent, outbound calls, or channel manager not configured
Channel manager phone selection timed out
POST /v1/{workspace_id}/calls/outbound HTTP/1.1
Host: api.platform.amigo.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 449
{
"phone_to": "text",
"use_case_id": "123e4567-e89b-12d3-a456-426614174000",
"patient_entity_id": "123e4567-e89b-12d3-a456-426614174000",
"patient_canonical_id": "text",
"reason": "text",
"service_id": "123e4567-e89b-12d3-a456-426614174000",
"system_prompt": "text",
"goal": "text",
"tags": [
"text"
],
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"derived_from_call_sid": "text",
"idempotency_key": "text",
"outbound_task_entity_id": "123e4567-e89b-12d3-a456-426614174000"
}{
"call_sid": "text",
"status": "text",
"phone_from": "text",
"setup_id": "123e4567-e89b-12d3-a456-426614174000",
"event_id": "123e4567-e89b-12d3-a456-426614174000"
}patient_entity_id and patient_canonical_id are mutually exclusive. Provide exactly one. Use patient_entity_id when you have the workspace entity UUID, or patient_canonical_id to reference the patient by world model canonical ID (source:resource_type:id).
Although the schema currently marks service_id as optional, the active voice runtime requires it. Supply it on every request.
How It Works
When you create an outbound call, the platform coordinates the initial request and voice runtime while exposing later states separately:
Validation - The Platform API verifies that the patient resolves to a projected
personin the workspace.Voice preparation and dial - The voice service validates the service and use case, selects an assigned caller ID, prepares the first agent audio, and then asks the carrier to create the call. Preparation or routing failure can reject the request before a usable call is returned.
Connection - If the destination answers and the agent joins successfully, the runtime begins the configured outbound experience. Startup latency still depends on the selected runtime and providers; there is no one-second speech guarantee.
Conversation - The service's runtime determines available context, state-machine behavior, and tools. Outbound and inbound calls share infrastructure, but they are not contractually identical and do not universally expose every tool or clinical field.
Completion - Status and post-call artifacts become available as their operational stores and asynchronous analyses update.
The initial status is typically queued; later carrier/runtime states can include ringing, in-progress, completed, failed, no-answer, or busy. Use the canonical Runs inventory (kind=conversation&channel=voice) to browse call runs. The legacy GET /calls and GET /calls/{call_id} compatibility routes return Deprecation: true and Sunset: 2026-07-01; POST /calls/outbound remains current.
Startup Instructions and Patient Identity
When you provide a goal, the Platform API turns it into a startup instruction. If system_prompt is also present, the goal is appended to that instruction before it is sent to the voice service. In the standard voice runtime, this instruction takes precedence over task-derived greeting context; it does not replace the agent definition or Context Graph.
The patient identifier validates that a projected person exists in the workspace and anchors the best-effort outbound.initiated lineage event. The direct call request does not pass that entity ID to the voice service as a dedicated patient-context field. Any caller lookup or ambient context therefore depends on the configured service and the runtime's own identity-resolution path.
patient_entity_id or patient_canonical_id
Patient validation and best-effort lineage anchor; not a dedicated runtime context payload
goal
Startup instruction formatted as a call objective
system_prompt
Explicit startup instruction for the call
system_prompt + goal
Goal appended to the explicit startup instruction
Neither system_prompt nor goal
The service's normal outbound greeting and context behavior
Phone Number Selection
The caller ID is always resolved from the use case. The current selector chooses one phone number at random from the numbers assigned to that outbound-voice use case. The resolved number is returned as phone_from; the compatibility setup_id field is currently null.
Response:
Callback Chains
When a call is a follow-up to a previous conversation, pass derived_from_call_sid with the original call's identifier. When lineage emission succeeds, that identifier is stored in the new outbound.initiated event so your own queries can correlate the two calls. It does not create a world-model graph edge or prove that either call completed.
When the relevant initiation events are emitted and projected successfully, the patient's timeline can expose the call identifiers for correlation. Treat that timeline as asynchronous evidence of initiation, not as a guaranteed relationship view or confirmation that either call completed.
External System Correlation
Use tags and metadata to connect calls to records in your other systems. When lineage emission succeeds, these values are stored in the outbound.initiated event. They remain queryable event data but are not guaranteed to appear in every built-in analytics view.
Tags and metadata can support custom event filtering and joins back to source systems when the initiation event is available.
Idempotency
Include an idempotency_key on requests that may need an ambiguous retry:
After a call request completes successfully, its response can be reused under the supplied key for one hour. A later request with the same key can return that response instead of placing another call. This does not serialize concurrent requests and cannot deduplicate a retry made before the first successful response is recorded. If an outcome is ambiguous, reconcile by call_sid or the Runs inventory before retrying. If you omit the key, the service generates one internally, so separate client retries do not share a deduplication key.
World Model Lineage
After the voice service accepts the outbound call, the Platform API attempts to emit an outbound.initiated event on the patient entity. Emission is best-effort: failure is logged, does not cancel the accepted call, and leaves event_id as null. A successfully emitted event captures:
Who requested the call - the API key identifier (not the secret)
Why - the
reasonandgoalyou providedWhat external systems are involved - your
tagsandmetadataWhere it fits in a sequence -
derived_from_call_sidif this is a callback
The event_id in the response points to this event. You can use it to:
Correlate initiation with available downstream call records by
call_sidQuery the patient's timeline for available initiation events
Build custom event analysis for API-initiated calls
Once the asynchronous world projection ingests the event, it can appear in the patient's timeline; read-after-write visibility is not immediate.
Error Responses
404
Patient entity does not exist in this workspace (or is not a person entity), or no phone number is available for the use_case_id
Verify the patient_entity_id exists via GET /v1/{workspace_id}/world/entities/{entity_id}. For use case 404s, check your phone number provisioning.
422
Invalid E.164 phone number, invalid UUID, missing required field, missing service_id at the active voice runtime, or invalid patient-identifier combination
Supply phone_to, use_case_id, service_id, reason, and exactly one patient identifier (patient_entity_id or patient_canonical_id).
429
Rate limit exceeded
Back off and retry. The limit applies per API key and per route (scoped to /calls/outbound).
502
The voice infrastructure returned an error
First reconcile whether a call was created. If retry is appropriate, preserve the same idempotency_key; a failure before the first successful response was recorded can still be ambiguous.
503
Voice agent or outbound calling is not configured for this workspace
Contact support to enable outbound calling.
504
Phone number selection timed out
Retry. If persistent, check phone number provisioning for the use case.
Rate Limits
The outbound call endpoint allows 1000 requests per minute, enforced per API key and per route. This limit is scoped to /calls/outbound only; other Platform API routes apply their own limits.
If you exceed the limit, you receive a 429 response. Preserve the same idempotency_key when retrying, but reconcile an ambiguous earlier attempt because the key does not make simultaneous retries or retries sent before the first successful response duplicate-proof.
Carrier-level constraints on individual phone numbers are enforced separately by the downstream voice carrier and are independent of this API rate limit.
Full Example
A CRM webhook fires when a patient's lab results are ready. Your backend calls the outbound API to notify them:
The goal is appended to the prompt sent to the configured service. Patient-context availability depends on that service's runtime and tools, so validate the intended context path before relying on clinical fields during the call.
Troubleshooting
Call connects but patient hears silence/hold music
The prepared agent audio or conference join did not become available as expected.
Verify service_id, the service release, and outbound voice setup; inspect the resulting run and call status.
503 Service Unavailable
Outbound calling is not enabled for this workspace, or the voice infrastructure is temporarily unavailable.
Contact support to verify outbound calling is configured.
404 Not Found on patient_entity_id
The entity doesn't exist, isn't in this workspace, or isn't a person entity type.
Check the entity via GET /v1/{workspace_id}/world/entities/{entity_id}.
Call rings but goes to voicemail
The patient did not answer.
Check the Runs inventory. A later call attempt should use a deliberate retry policy and a new idempotency key; derived_from_call_sid can record correlation metadata.
Agent speaks but has no patient context
The direct endpoint validates the patient for lineage but does not pass the entity ID as a dedicated voice-runtime context field. Caller lookup, projection freshness, or service configuration may also be incomplete.
Verify the service's identity-resolution and world-tool path instead of assuming the request's patient identifier preloads context.
Last updated
Was this helpful?

