# Outbound

{% hint style="info" %}
Outbound text conversations support entity-based resolution. When the platform knows the patient ahead of time (via entity ID), it loads their full context - clinical history, prior interactions, and preferences - before the first message is sent, rather than relying solely on phone number matching.
{% endhint %}

## Ringless Voicemail

The platform supports ringless voicemail delivery - pre-recorded audio messages deposited directly into a recipient's voicemail box without ringing their phone. This is useful for appointment reminders, care follow-ups, and other outreach where a non-intrusive notification is preferable to a live call.

Ringless voicemail sends require:

* A use case configured for ringless voicemail delivery
* A US phone number with voice capability assigned to the use case
* An MP3 audio file between 10 and 60 seconds long (max 8 MB)
* A US recipient phone number

The platform manages sender registration, audio storage, delivery dispatch, and status tracking. Each voicemail progresses through a lifecycle: pending after submission, then transitioning to delivered, not delivered, skipped, or failed based on carrier feedback. Delivery status updates arrive asynchronously via webhook and are recorded against the voicemail record.

Ringless voicemail is currently supported for US-to-US delivery only.

The outbound system initiates contact based on clinical rules, care plans, and decisions the agent makes during conversations. Outbound tasks are first-class entities in the [world model](/data/world-model.md), so their outcomes are tracked, auditable, and feed back into the patient's record automatically.

Each outbound task carries the full patient context, so when the conversation starts, the agent already knows why it is calling and what it needs to accomplish.

## Outbound

### Caller ID Resolution

When an outbound task is scheduled, the platform resolves which phone number to use as the caller ID at scheduling time rather than waiting until the call is placed. This means configuration errors - such as having no outbound-capable phone number in the workspace - surface immediately when the task is created, not minutes later when the system attempts to dial.

If the outbound task is linked to a specific service, the platform prefers the phone number already assigned to that service. This keeps caller ID consistent - patients see the same number they would use to call back. If no service-specific number is available, the platform selects any active outbound-capable number in the workspace.

### Automated Outbound Campaigns

The platform supports automated daily outbound calling campaigns that select eligible patients from the world model and place calls without manual list management. The campaign engine queries the world model for patient entities with valid phone numbers, filters out inactive or test records, and applies attempt limits and cooldown periods to prevent over-contact.

Key campaign behaviors:

* **Eligibility filtering** - Patients are selected based on entity status, phone number validity, and production data sources. Patients who have reached the maximum attempt count or been contacted within the cooldown window are automatically excluded.
* **Recipient allowlisting** - During ramp-up, campaigns can be restricted to a specific set of phone numbers. When the allowlist is cleared, the campaign dials all eligible patients.
* **Idempotent call placement** - Each call carries a date-scoped idempotency key, preventing duplicate calls if a campaign is retried on the same day.
* **Source attribution** - Campaign-originated calls carry tags and metadata that distinguish them from manually initiated outbound calls in analytics.
* **Circuit breaker** - Consecutive failures trigger an automatic stop to avoid wasting resources against an unavailable downstream system. Partial results are persisted before termination.
* **Manual override** - Operators can specify an explicit call list for targeted test runs, bypassing eligibility filters entirely.

### Outbound Task Data Model

Each outbound task is tracked as a dedicated entity in the world model with structured fields for scheduling, retry logic, and outcome tracking. The platform projects outbound task events into typed columns on the entity snapshot, so downstream queries and analytics can filter and sort on native field types rather than parsing nested data.

Outbound task fields include:

* **Status** - Current lifecycle state: scheduled, dispatched, completed, failed, cancelled, or snoozed. Status is derived from the most recent event, with automatic re-scheduling on retriable failures when attempts remain.
* **Phone number** - The destination phone number for the outbound call.
* **Reason and goal** - Why the call is being made and what the agent should accomplish.
* **Priority** - Numeric priority for dispatch ordering. Higher-priority tasks are dispatched first.
* **Scheduling** - When the task is scheduled, when the next attempt should occur, and an optional business-hours window that constrains when calls are placed.
* **Retry configuration** - Maximum number of attempts and backoff interval between retries.
* **Attempt tracking** - Current attempt count, call identifier for the active or most recent attempt, and outcome of the last attempt.
* **Patient link** - Reference to the patient entity associated with the outbound task.
* **Service link** - Reference to the service (agent configuration) that handles the call. Patterns

The platform supports six distinct patterns for initiating outbound contact, plus a direct API path for on-demand calls.

### Scheduled

Time-triggered tasks. Appointment reminders 48 hours before a visit. Post-discharge check-ins on day 3 and day 7. Medication refill reminders. These are the simplest pattern - a task fires at a configured time. [Triggers](/reference/glossary.md#t) provide the scheduling mechanism: a cron expression defines when to fire, and the bound action handles the outreach logic.

### Event-Reactive

Triggered by data changes in the world model. A lab result arrives and the agent calls to discuss it. A referral is approved and the agent schedules the follow-up. Insurance verification completes and the agent confirms coverage with the patient. Any entity change can trigger an outbound task. Triggers can also be configured with event filters to dispatch actions in response to specific event types.

### Webhook-Driven

External systems can fire triggers directly via inbound webhooks. A CRM posts a contact-updated event, a scheduling system sends an appointment-created notification, or a workflow automation tool pushes a task completion signal. The platform receives the webhook, verifies the HMAC signature, and fires the linked trigger.

Webhook destinations support event type filtering - each destination can define an `accepted_event_types` whitelist so only relevant events fire the trigger. The event type is extracted from the signed request body (checking common payload fields like `type`, `event_type`, `event`, and `action` in priority order), not from unsigned headers, which prevents event type spoofing via replay attacks. Events that don't match the whitelist are rejected before the trigger fires.

When transient network errors occur during trigger execution, the platform retries with exponential backoff. The retry count is configurable per webhook destination and only applies to connection-level failures - application errors are not retried to avoid duplicate events from non-idempotent operations.

### Continuous Monitoring

Driven by patient state over time. Adherence tracking for chronic care programs. Care plan milestone check-ins. Gaps in care that persist beyond a threshold. The platform evaluates patient state on a recurring basis and creates tasks when conditions are met.

### Conversational Follow-Through

Promises made during calls become tasks automatically. When an agent says "I'll call you back tomorrow at 10 with your results," the platform creates a scheduled outbound task. No human needs to remember. No ticket needs to be filed. The commitment is captured and honored.

### Orchestrated Campaigns

Goal-driven outreach across patient populations. Annual wellness visit scheduling for an entire panel. Post-surgical follow-up for all patients discharged this week. Campaigns have configurable priority and pacing so they do not overwhelm staff or phone lines.

### Direct API

For on-demand calls that do not fit a recurring schedule or trigger pattern. A care coordinator clicks "call now" in the developer console. A CRM deal-stage change fires a webhook that calls the outbound API directly. A backend process determines a patient needs an immediate callback after a failed call attempt.

The direct API requires only an API key and two pieces of context: which patient the call is about and why. No campaign, trigger, or scheduling configuration is needed. The platform validates that the patient exists, places the call, and records a world model event capturing the full context of who requested it and why.

This is the fastest path to an outbound call. Everything else - triggers, campaigns, scheduled tasks - is built for recurring, automated outreach. The direct API is built for the moment a human or system decides "this patient needs a call right now."

## Programmatic Outbound Calls

The platform exposes outbound call creation as a public API endpoint. SDK users, developer console operators, and external integrations can dispatch outbound calls directly without configuring triggers or campaigns. Only an API key is needed.

Every programmatic outbound call requires a patient entity reference and a reason. This ensures that every API-triggered call is traceable in the world model from the moment of initiation - before the call connects. The platform validates that the patient entity exists in the workspace, preventing orphan references or broken lineage chains.

When a call is created, the platform records a world model event capturing the full context: who requested it (identified by API key), why (the stated reason), which patient, and any metadata the caller attached. This event is linked to the patient's timeline immediately, making the call visible alongside agent-scheduled calls, webhook-triggered calls, and manually dispatched calls in the same unified view.

### Call context enrichment

Callers can provide an optional goal describing what the call should accomplish. The platform injects this goal into the agent's context so it knows the objective before the patient answers. The agent also receives the patient's full clinical profile - demographics, active conditions, medications, upcoming appointments, and prior interaction history - loaded automatically from the world model during the dial phase.

Tags and arbitrary metadata can be attached for downstream analytics and external system correlation. A CRM integration might attach the opportunity ID. A care management workflow might tag calls by program. An EHR integration might link calls to specific orders or results. These values are preserved in the world model event and available in analytics queries.

### Callback lineage

If the call is a callback from a prior conversation, the caller can reference the original call identifier. This creates an explicit lineage chain between calls, so the platform tracks the full outreach sequence - first attempt, second attempt, successful callback - rather than treating each call as an isolated interaction. The patient's timeline shows the complete chain.

### Idempotency and rate limiting

Outbound call creation supports idempotency - supplying a unique key with each request allows safe retries without creating duplicate calls. The API returns a call identifier, initial status, and the world model event identifier so the calling system can track both the telephony lifecycle and the data lineage.

Outbound call creation is rate-limited to 1,000 requests per minute per API key - high enough for batch campaign dispatches without serialization delays, while still preventing runaway automation. The voice infrastructure applies its own per-source-number rate limit independently, so both the API gateway and the voice layer enforce safe call volumes. See [Performance Characteristics](/reference/performance.md#api-rate-limits) for the full rate limit table.

### Integration patterns

This enables integration patterns like CRM-triggered calls (a deal stage change fires an outbound call), scheduling system callbacks (a patient requests a callback through a portal), EHR-driven outreach (a lab result triggers a follow-up call), post-visit follow-ups (a discharge event triggers a wellness check), and workflow automation (a Zapier or webhook-driven pipeline dispatches calls based on external events).

## Dispatch Pipeline

When an outbound task is created — whether from a webhook, a trigger, the API, or an agent decision during a call — it flows through a multi-stage pipeline before a call is placed.

```mermaid
flowchart TD
    A[Task Created] -->|outbound.scheduled event| B[World Model]
    B -->|Streaming pipeline| C[Entity Projection]
    C -->|Reverse ETL every 2 min| D[Queryable Entity Store]
    D -->|Dispatch loop every 30s| E{Due?}
    E -->|next_attempt_at <= now| F{Business hours?}
    E -->|Not yet due| D
    F -->|In window| G[Acquire Lock]
    F -->|Outside window| D
    G --> H[Place Call]
    H -->|Success| I[outbound.dispatched]
    H -->|Failure| J{Retries left?}
    J -->|Yes| K[Reschedule with backoff]
    J -->|No| L[outbound.failed]
    K --> D
```

Each outbound task is a first-class entity with typed fields — status, priority, phone number, scheduling window, and retry configuration are all queryable columns, not nested data. The dispatch loop queries these fields directly with indexed predicates, so tasks are discovered and dispatched efficiently even at scale.

### Timing

From task creation to call placement, expect 2–3 minutes in the typical case:

* Event processing and entity projection: seconds
* Entity sync to the queryable store: up to 2 minutes (runs on a fixed interval)
* Dispatch loop: up to 30 seconds (polls on a fixed interval)
* Lock acquisition and call setup: under 1 second

For the direct API path, calls are dispatched immediately — bypassing the task lifecycle entirely.

## Dispatch and Channel Selection

The dispatch system evaluates which tasks are due, respects business hours in the patient's timezone, and checks contact preferences before initiating. Tasks carry full patient context so the agent is pre-loaded when the conversation begins.

Outbound can trigger voice calls or text sessions. The platform picks the channel based on patient preferences and contact history. If a voice call goes unanswered, the system follows retry logic - try again at a different time, leave a voicemail, or fall back to text. See [scheduling and outreach](/use-cases/use-cases/scheduling-outreach.md) for a full workflow example.

## Retry and Prioritization

Tasks have configurable priority levels (1 through 10), retry windows with backoff, and business hours constraints. A priority-1 task (urgent lab result) will be attempted sooner and more aggressively than a priority-8 task (annual wellness reminder).

Failed attempts are tracked as events. The full outreach history is visible - how many attempts, which channels, what happened each time. This gives operations teams the data they need to tune retry strategies and identify unreachable patients.

## Task Creation

Outbound tasks can be created in two ways:

* **Trigger-driven** - When a webhook trigger's action is configured as an outbound call, the platform creates the outbound task entity and scheduling event deterministically, without invoking the LLM reasoning loop. This is the recommended path for automated outbound workflows where the call parameters are fully known at trigger time. It is faster, cheaper, and produces consistent results.
* **Manual or API-driven** - Tasks can also be created through the API or other automation pathways that write scheduling events directly to the world model.

Both creation paths produce the same outbound task entity with the same fields and lifecycle behavior.

## Task Lifecycle

```mermaid
flowchart LR
    P[Pending] --> D[Dispatched]
    D --> R[Running]
    R --> C[Completed]
    R --> F[Failed]
    R --> T[Timeout]
    P --> X[Cancelled]
    F -->|Retry| P
```

Every outbound task moves through a clear lifecycle:

| State          | Meaning                                                          |
| -------------- | ---------------------------------------------------------------- |
| **Pending**    | Task created, waiting for its dispatch window                    |
| **Dispatched** | Task sent to the agent for execution                             |
| **Running**    | Agent is actively handling the interaction                       |
| **Completed**  | Interaction finished successfully                                |
| **Failed**     | All retry attempts exhausted                                     |
| **Cancelled**  | Task removed before completion (e.g., appointment was cancelled) |
| **Timeout**    | Task exceeded its maximum execution window                       |

Each transition is recorded as an event in the world model. Downstream systems can react to these transitions - for example, escalating to a human coordinator when a task fails after all retries.

Direct API calls bypass the task lifecycle - the call is dispatched immediately. The world model event tracks initiation, and subsequent call lifecycle events (connected, completed, failed) are recorded on the patient's timeline just like any other call.

## World Model Integration

Because outbound tasks are entities in the [world model](/data/world-model.md), they participate in the same projection, confidence scoring, and analytics as everything else. You can query outbound task status, success rates, and patient response patterns through the same analytics layer used for clinical data.

Outbound outcomes feed back into the patient record. A completed reminder call updates the patient's engagement history. A failed outreach attempt is visible to the next agent or human who interacts with that patient. API-initiated calls carry their metadata and tags through to the analytics layer, so you can filter and segment outreach by source system, campaign, or any other dimension you attach.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.amigo.ai/channels/outbound.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
