> For the complete documentation index, see [llms.txt](https://docs.ixhello.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ixhello.com/ixhc2/integrations/outbound-calling-api-user-guide.md).

# Outbound Calling API - User Guide

### Overview

The **Outbound Calling API** enables external applications to programmatically initiate outbound voice calls and execute conversational flows on the platform. External systems such as **iX Dialer**, **CRM platforms**, customer engagement solutions, and demo orchestration tools can trigger a voice interaction using a single API request.

When a call is initiated, the platform dials the specified PSTN number or SIP destination. Once the recipient answers, the designated flow is launched with **full persona integrity**, ensuring that the configured voice, instructions, prompts, AI behavior, integrations, and business logic are applied from the very first interaction.

This capability allows organizations to automate customer outreach, notifications, testing scenarios, and voice-driven business processes while leveraging the full capabilities of conversational AI.

***

## Key Benefits

### Proactive Engagement

Initiate outbound calls for:

* Appointment reminders
* Service notifications
* Policy renewals
* Payment reminders
* Customer follow-ups
* Emergency communications

### Automation

Automate voice-based workflows without requiring manual agent intervention.

Common scenarios include:

* Customer verification
* Information collection
* Automated alerts
* Workflow testing
* Survey execution

### Interoperability

Integrate seamlessly with telephony and contact center platforms including:

* PSTN
* SIP
* Genesys
* Twilio
* CRM systems
* iX Dialer
* Demo orchestration platforms

***

## Core Capabilities

The Outbound Calling API provides a complete framework for executing, tracking, and managing outbound conversations.

#### Programmatic Call Initiation

Initiate outbound voice interactions using a single API request.

Required information:

* Organization ID
* Flow ID
* Destination Number (PSTN or SIP)

#### Full Flow Execution

Outbound calls execute the selected flow exactly as an inbound call would.

Supported capabilities include:

* LLM interactions
* Voice prompts
* Text-to-Speech (TTS)
* Data Actions
* API integrations
* Session variables
* Conditional routing
* Conversational AI agents

#### Flexible Result Delivery

Choose one of three response mechanisms:

* Synchronous
* Polling
* Webhook

#### Session Variables

Inject contextual information at the time the call is created.

Examples:

* Customer Name
* Account Number
* Policy ID
* Appointment Details
* CRM Reference Number

#### Call Analysis

Optionally detect whether the call was answered by:

* Live Person
* Answering Machine
* Fax Machine
* Unknown Recipient Type

***

## Typical Workflow

Plain Text1External System2|3| POST Call Request4v5Outbound Calling API6|7v8Telephony Infrastructure9|10v11Recipient Answers12|13v14Flow Starts15|16v17Call Outcome Delivered18(sync / poll / webhook)Show more lines

***

## MVP Scope

### Included

✅ Outbound PSTN Calling

✅ SIP Calling

✅ Flow Execution

✅ Session Variables

✅ Call Analysis (AMD)

✅ Status Tracking

✅ Webhook Notifications

✅ API Key Authentication

***

### Out of Scope

The following are not supported in the MVP release:

* Scheduled or deferred calls
* Batch or campaign dialing
* Admin console/dashboard
* Call recording management
* Outbound SMS
* Outbound chat channels
* Time-based queuing
* Long-term call persistence

***

## Authentication

All endpoints require API Key authentication.

### Authorization Header

HTTP1Authorization: Bearer \<api\_key>Show more lines

#### API Key Management

* API keys are provisioned per organization.
* API keys are securely stored in Secrets Manager.
* Shared with the Headless Execution API.

#### Organization Isolation

Security is enforced at the organization level.

An API key:

✅ Can access flows belonging to its organization.

❌ Cannot access flows belonging to another organization.

❌ Cannot retrieve call information from another organization.

The system validates the `orgId` in every request against the API key.

***

## Result Delivery Modes

Every call request must specify a delivery mode that determines how results are returned.

***

## 1. Sync Mode

### Overview

The HTTP connection remains open until the call reaches a terminal state or a timeout occurs.

The complete call outcome is returned as part of the API response.

#### Best Suited For

* Testing
* Demos
* Very short flows

#### Characteristics

| Feature                  | Value                 |
| ------------------------ | --------------------- |
| Processing Model         | Blocking              |
| Initial Response         | Wait until completion |
| HTTP Response            | 200 OK                |
| Maximum Wait Time        | 30 Seconds            |
| Public Endpoint Required | No                    |

#### Flow

Plain Text1POST Request2|3v4Call Initiated5|6v7Call Runs8|9v10Completed / Failed11|12v13Response ReturnedShow more lines

#### Timeout Handling

If a call exceeds 30 seconds:

HTTP1504 Gateway TimeoutShow more lines

The call continues running and can be tracked using:

HTTP1GET /calls/{sessionId}Show more lines

***

## 2. Poll Mode

### Overview

The API immediately returns a Session ID.

The client periodically polls the platform to retrieve call progress and final outcomes.

#### Best Suited For

* CRM systems
* Backend services
* Workflow engines

#### Characteristics

| Feature                  | Value        |
| ------------------------ | ------------ |
| Processing Model         | Asynchronous |
| Initial Response         | Immediate    |
| HTTP Response            | 201 Created  |
| Public Endpoint Required | No           |

#### Flow

Plain Text1POST Call2|3▼4201 Created5(SessionId)6|7▼8GET Status9|10▼11Queued12Ringing13Answered14CompletedShow more lines

***

## 3. Webhook Mode

### Overview

The API immediately returns a Session ID and sends lifecycle updates to the configured webhook endpoint.

#### Best Suited For

* Real-time integrations
* Enterprise workflows
* Event-driven architectures

#### Characteristics

| Feature                  | Value        |
| ------------------------ | ------------ |
| Processing Model         | Event Driven |
| Initial Response         | Immediate    |
| HTTP Response            | 201 Created  |
| Public Endpoint Required | Yes          |

#### Events Delivered

* `call.answered`
* `call.failed`
* `call.completed`

#### Delivery Model

Webhook delivery is:

* Best effort
* Not retried in MVP
* Logged on failure

***

## Comparison of Result Delivery Modes

| Feature                  | Sync             | Poll        | Webhook     |
| ------------------------ | ---------------- | ----------- | ----------- |
| Initial Response         | After completion | Immediate   | Immediate   |
| HTTP Status              | 200 OK           | 201 Created | 201 Created |
| Timeout Limit            | 30 seconds       | N/A         | N/A         |
| Requires Public Endpoint | No               | No          | Yes         |
| Suitable for Long Calls  | No               | Yes         | Yes         |
| Real-Time Notifications  | No               | No          | Yes         |

***

## Session Affinity in Poll Mode

Poll mode requires session affinity because Channel Gateway instances do not share a persistent call-state store.

Clients must:

1. Store cookies returned in the initiation response.
2. Include those cookies in subsequent status requests.

This ensures requests are routed to the same gateway instance.

***

### Detailed Call Lifecycle

**Session ID ownership (async modes):** For `poll` and `webhook` modes, the Channel Gateway pre-generates the session ID at request time, persists it with `Queued` status, and returns it in the `201 Created` response. The session ID is also forwarded to the Media Server in the outbound call request. When the recipient answers, the Media Server reports the answered call back to the Channel Gateway using this pre-assigned ID, enabling immediate session matching without an additional round-trip. For `sync` mode the session ID is generated at the same point but not returned until the call reaches a terminal state.

#### Queued

The call has been accepted and is waiting for telephony resources.

#### Ringing

The destination number is currently being dialed.

#### Answered

The recipient has answered.

At this point:

* AMD executes (if enabled)
* Session variables are injected
* Flow execution begins

#### Completed

The call completed successfully because:

* The flow reached an end node
* The participant disconnected normally
* The interaction finished successfully

#### Failed

The call could not be completed.

A failure reason is always provided.

***

## Call Status Values

| Status    | Description                          |
| --------- | ------------------------------------ |
| Queued    | Request accepted and waiting to dial |
| Ringing   | Destination is being dialed          |
| Answered  | Call was answered                    |
| Completed | Call completed successfully          |
| Failed    | Call failed                          |

***

## Failure Reasons

| Value                  | Description                                                                                                                                                                                                                                     |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| no\_answer             | Destination did not answer within the ring timeout (default 30 s)                                                                                                                                                                               |
| busy                   | Destination was busy                                                                                                                                                                                                                            |
| trunk\_unavailable     | No telephony trunk was available at call time                                                                                                                                                                                                   |
| unroutable\_number     | Destination number could not be routed (e.g. invalid region)                                                                                                                                                                                    |
| session\_start\_failed | Runtime Engine could not create a session upon call connection (flow not found, invalid flow configuration, or any other RTE rejection); a technical difficulty prompt is played to the recipient. Upfront flow ID validation is not performed. |
| flow\_error            | Unrecoverable error during flow execution after a session was successfully started                                                                                                                                                              |
| fax                    | AMD detected a fax machine; call was terminated without starting a flow session                                                                                                                                                                 |
| answering\_machine     | AMD detected an answering machine and `"answering_machine"` was not in the `callAnalysis` array; call terminated without starting a flow session                                                                                                |
| unknown                | AMD result was inconclusive and `"unknown"` was not in the `callAnalysis` array; call terminated without starting a flow session                                                                                                                |

***

## Call Analysis (AMD)

Answering Machine Detection (AMD) allows the platform to determine who answered an outbound call before executing the flow.

Supported outcomes:

* live\_person
* answering\_machine
* fax

The platform supports two mutually exclusive AMD approaches.

***

### Option A — Channel-level AMD (`callAnalysis: [...]`)

When `callAnalysis` is included in the request body as an array of accepted AMD outcomes, the Channel Gateway invokes the telephony infrastructure's built-in answering machine detection immediately upon pickup, *before* the Runtime Engine flow session is created. The flow session is created only if the detected result is in the array.

* Valid values: `live_person`, `answering_machine`.
* The AMD result is recorded as `callAnalysisResult` and included in all call outcome payloads (poll status, sync response, webhook callback).
* **Fast** — uses audio-signal heuristics; result is available within a few seconds of pickup.
* **Lower accuracy** — cannot understand language; may mis-classify noisy environments.
* `fax` always terminates the call regardless of the array — no flow session is created.

| `callAnalysisResult` | Meaning                                                | Flow session started?                                                                  |
| -------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------- |
| live\_person         | A human answered                                       | Yes, if in `callAnalysis` array                                                        |
| answering\_machine   | An answering machine / voicemail greeting was detected | Yes if in array — flow can leave a message; No if omitted from array — call terminates |
| fax                  | A fax tone was detected                                | No — always terminates                                                                 |
| unknown              | AMD was inconclusive or timed out                      | Yes if in array; No if omitted — call terminates                                       |

***

### Option B: Flow-Level Semantic Analysis

When `callAnalysis` is omitted, the flow session starts immediately on pickup with no AMD step. Flow designers can add an **Agent node** configured for call analysis to semantically analyse the initial audio.

* **Higher accuracy** — language-level understanding can distinguish live greetings from machine greetings more reliably.
* **Requires flow authoring** — the Agent node must be explicitly added and configured in the flow.
* `callAnalysisResult` is *absent* from all call outcome payloads when this approach is used.

**Recommendation for iX Demos:** Start with `callAnalysis: ["live_person"]` for simplicity. If you also want to handle answering machines (e.g. to leave a voicemail), add `"answering_machine"` to the array. If accuracy is insufficient for a specific use case, implement flow-level semantic analysis instead.

***

### Error Responses

All endpoints use a consistent error envelope:

```
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description"
  }
}
```

| HTTP | Code                  | Description                                                                                 |
| ---- | --------------------- | ------------------------------------------------------------------------------------------- |
| 400  | INVALID\_REQUEST      | Malformed request body or missing required fields                                           |
| 400  | INVALID\_DESTINATION  | `destinationNumber` is not a valid E.164 number or SIP address                              |
| 400  | INVALID\_WEBHOOK\_URL | `webhookUrl` is missing, not HTTPS, or otherwise invalid                                    |
| 401  | AUTH\_HEADER\_MISSING | `Authorization` header was not provided                                                     |
| 401  | INVALID\_TOKEN        | API key is invalid, revoked, or expired                                                     |
| 403  | PERMISSION\_DENIED    | Org does not have the `outbound_calling` permission, or the flow belongs to a different org |
| 404  | NOT\_FOUND            | Session identifier not found                                                                |
| 429  | RATE\_LIMIT\_EXCEEDED | API Gateway request throttle exceeded                                                       |
| 504  | SYNC\_TIMEOUT         | `sync` mode only: call did not complete within the maximum API Gateway timeout (30 s)       |

***

## REST API Endpoints

Two endpoints. One to fire a call, one to check its status.

| Method | Endpoint                                           | Purpose                                                     |
| ------ | -------------------------------------------------- | ----------------------------------------------------------- |
| POST   | `/cgw/outbound/v1/orgs/:orgId/flows/:flowId/calls` | Initiate an outbound call                                   |
| GET    | `/cgw/outbound/v1/orgs/:orgId/calls/:sessionId`    | Get call status (for `poll` mode or after a `sync` timeout) |

***

### Initiate Outbound Call

#### Endpoint

POST /cgw/outbound/v1/orgs/{orgId}/flows/{flowId}/calls

#### Purpose

Triggers an outbound call and executes the selected flow.

Triggers an immediate outbound PSTN/SIP call using the specified flow. Behaviour after request acceptance depends on the `mode` field.

**Path Parameters**

| Parameter | Type | Required | Description                                                        |
| --------- | ---- | -------- | ------------------------------------------------------------------ |
| orgId     | UUID | Yes      | Organisation UUID. Must match the org associated with the API key. |
| flowId    | UUID | Yes      | UUID of the flow to execute. The flow must belong to the org.      |

**Request Body**

```
{
  "destinationNumber": "+15551234567",
  "callerId": "+15559990000",
  "mode": "poll",
  "variables": {
    "customerName": "Jane Doe",
    "accountNumber": "12345"
  },
  "callAnalysis": ["live_person", "answering_machine"],
  "webhookUrl": "https://example.com/callbacks/calls",   // required when mode is "webhook"
  "webhookAuth": "a-shared-secret-value",   // optional: used to sign callbacks (see Webhook Callback section)
  "metadata": {
    "externalSessionId": "crm-call-abc123",
    "campaign": "renewal-2026"
  }
}
```

| Field             | Type      | Required    | Description                                                                                                                                                                                                                                                                                                                                     |
| ----------------- | --------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| destinationNumber | string    | Yes         | E.164 PSTN number (e.g. `+15551234567`) or SIP address (e.g. `sip:user@domain.com`)                                                                                                                                                                                                                                                             |
| callerId          | string    | No          | The caller ID (ANI) presented to the destination, e.g. `+15559990000` or a SIP URI. **Strongly recommended** — when omitted, the platform falls back to a synthetic local identifier that is not a routable caller ID and should not be relied on for production calls.                                                                         |
| mode              | enum      | Yes         | Result delivery mode: `"sync"`, `"poll"`, or `"webhook"`                                                                                                                                                                                                                                                                                        |
| variables         | object    | No          | Key-value pairs injected into the flow as **session variables** at the start of the call. Accessible within flow nodes at runtime (e.g. use a customer name in a prompt). Not echoed in API responses.                                                                                                                                          |
| callAnalysis      | string\[] | No          | Array of accepted AMD outcome values that trigger flow session creation. AMD is enabled when present. Valid values: `live_person`, `answering_machine`. Results not in the array (or `fax`, which always terminates) cause the call to terminate without a session. The AMD result is always recorded in the call outcome. Omit to disable AMD. |
| webhookUrl        | string    | Conditional | Required when `mode` is `"webhook"`. Receives a POST at each lifecycle event: `call.answered`, `call.failed`, `call.completed`.                                                                                                                                                                                                                 |
| webhookAuth       | string    | No          | Optional shared secret. When provided, it is used as the HMAC-SHA256 key to compute the `X-Signature` header on every webhook callback (see Webhook Callback section). It is **not** forwarded as an `Authorization` header. Stored encrypted; never returned in any API response. Only meaningful when `mode` is `"webhook"`.                  |
| metadata          | object    | No          | Opaque key-value pairs for the caller's own correlation purposes. **Not** injected into the flow as session variables. Echoed verbatim in all responses (201, sync 200, GET 200, and webhook callbacks).                                                                                                                                        |

**Response — `poll` or `webhook` mode (201 Created)**

Returned immediately. The call is queued asynchronously.

```
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Queued",
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "createdAt": "2026-04-24T10:00:00.000Z"
}
```

**Response — `sync` mode, call completed (200 OK)**

Returned after the call reaches a terminal state. The HTTP connection is held open until completion or the 30-second API Gateway timeout.

```
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Completed",
  "durationSeconds": 142,
  "callAnalysisResult": "live_person",   // only present when callAnalysis was provided
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "completedAt": "2026-04-24T10:02:22.000Z"
}
```

**Response — `sync` mode, call failed (200 OK)**

```
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Failed",
  "failureReason": "no_answer",
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "completedAt": "2026-04-24T10:00:32.000Z"
}
```

**Response — `sync` mode timeout (504 Gateway Timeout)**

Returned when the call has not reached a terminal state within 30 seconds. The call continues processing and its status remains queryable via `GET .../calls/:sessionId`.

***

### Get Call Status

#### Endpoint

GET /cgw/outbound/v1/orgs/{orgId}/calls/{sessionId}

#### Purpose

Returns the current or final status of a call.

Common use cases:

* Poll Mode tracking
* Retrieving results after Sync timeout
* Monitoring active calls

Retrieves the current status of an outbound call. Can be called at any point during the call lifecycle — use it to poll for completion in `poll` mode, or to retrieve the final outcome after a `sync` timeout.

**Path Parameters**

| Parameter | Type | Required | Description                                                        |
| --------- | ---- | -------- | ------------------------------------------------------------------ |
| orgId     | UUID | Yes      | Organisation UUID. Must match the org associated with the API key. |
| sessionId | UUID | Yes      | UUID of the call session, returned by the initiation endpoint      |

**Response (200 OK) — in-progress call**

```
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Answered",
  "callAnalysisResult": "live_person",   // only present when callAnalysis was provided
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "createdAt": "2026-04-24T10:00:00.000Z",
  "answeredAt": "2026-04-24T10:00:04.500Z",
  "completedAt": null
}
```

**Response (200 OK) — completed call**

```
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Completed",
  "durationSeconds": 142,
  "callAnalysisResult": "live_person",
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "createdAt": "2026-04-24T10:00:00.000Z",
  "answeredAt": "2026-04-24T10:00:04.500Z",
  "completedAt": "2026-04-24T10:02:22.000Z"
}
```

**Response Fields**

| Field              | Type   | Description                                                                                                 |
| ------------------ | ------ | ----------------------------------------------------------------------------------------------------------- |
| sessionId          | UUID   | UUID uniquely identifying this call session                                                                 |
| flowId             | UUID   | UUID of the flow that was executed                                                                          |
| status             | enum   | Current call status — see status table in Call Lifecycle                                                    |
| durationSeconds    | number | Call duration in seconds. Only present when `status` is `Completed` and the call was answered.              |
| failureReason      | string | Only present when `status` is `Failed` — see failureReason values in Call Lifecycle                         |
| callAnalysisResult | enum   | Only present when `callAnalysis` was provided. Values: `live_person`, `answering_machine`, `fax`, `unknown` |
| metadata           | object | The metadata provided in the original request, echoed back for correlation                                  |
| createdAt          | string | ISO 8601 timestamp when the call was accepted                                                               |
| answeredAt         | string | ISO 8601 timestamp when the recipient answered. Null if not yet answered.                                   |
| completedAt        | string | ISO 8601 timestamp when the call reached a terminal state. Null if still in progress.                       |

***

### Webhook Events

When `mode` is `"webhook"`, the platform fires an HTTP POST to your `webhookUrl` at each of the following lifecycle events. Each payload includes an `event` field so your receiver can act without tracking state.

| Event          | `event` value    | Fired when                                                                        |
| -------------- | ---------------- | --------------------------------------------------------------------------------- |
| Call answered  | `call.answered`  | Recipient picks up; `callAnalysisResult` included when `callAnalysis` is provided |
| Call failed    | `call.failed`    | Call fails at any stage — not answered, busy, fax detected, or flow error         |
| Call completed | `call.completed` | Flow ends normally (`Completed` terminal state)                                   |

#### Receiver Authentication

**Resolved — Webhook Payload Signing (`X-Signature`)**\
\
`X-Signature` is implemented as an HMAC-SHA256 signature of the JSON body, computed using `webhookAuth` (the caller-supplied value from the initiation request) as the signing secret. There is **no** separate per-org signing secret, and `webhookAuth` is **not** forwarded as an `Authorization` header on callbacks — its only purpose is to sign the payload.

Webhook receivers should verify the `X-Signature` header to confirm a callback originated from the platform:

1. **`webhookAuth`** — a shared secret supplied in the initiation request. If omitted, callbacks are still sent but signed with an empty secret (i.e. effectively unsigned) — supplying a strong secret is recommended for any production integration.
2. **`X-Signature`** — `sha256=<hex>`, computed as `HMAC-SHA256(webhookAuth, rawRequestBody)`. Recompute this over the exact raw body you received and compare against the header to verify integrity.

**Recommended practice:** always supply `webhookAuth` and verify `X-Signature` on every callback. Since `webhookAuth` is not sent as an `Authorization` header, it cannot be used by itself to gate access at your receiver — use a dedicated network/API-level control (e.g. a secret path segment or IP allowlist) if you also need to restrict who can call your endpoint.Each event callback is delivered on a best-effort basis. If the delivery attempt fails (non-2xx response or connection timeout), the failure is logged and the call status remains queryable via `GET .../calls/:sessionId`. No retries are performed in the initial implementation.

**Request Headers**

| Header       | Description                                                                                                                                                                                     |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Content-Type | `application/json`                                                                                                                                                                              |
| X-Signature  | `sha256=<hex>` — HMAC-SHA256 signature of the raw request body, computed using `webhookAuth` as the secret. Allows you to verify the payload was sent by the platform and wasn't tampered with. |

***

### **Payload —** call.answered

Triggered when the recipient picks up. When `callAnalysis` is provided, AMD completes before the flow session is created, so `callAnalysisResult` is already available in this payload.

Sent when the recipient answers.

```
{
  "event": "call.answered",
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Answered",
  "callAnalysisResult": "live_person",   // only present when callAnalysis was provided
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "answeredAt": "2026-04-24T10:00:04.500Z"
}
```

***

### **Payload —** call.failed

Triggered when the call fails at any stage. `callAnalysisResult` is present when AMD caused the termination (e.g., `failureReason: "fax"` or `"answering_machine"` when the result was not in the `callAnalysis` array). For calls that fail *after* being answered, a `call.answered` was already sent before this.

Sent when the call fails.

```
{
  "event": "call.failed",
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Failed",
  "failureReason": "no_answer",
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "completedAt": "2026-04-24T10:00:32.000Z"
}
```

***

### **Payload —** call.completed

Triggered when the flow ends normally. `callAnalysisResult` is echoed from the earlier `call.answered` payload for convenience.

Sends when the call ends.

```
{
  "event": "call.completed",
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "status": "Completed",
  "durationSeconds": 142,
  "callAnalysisResult": "live_person",   // echoed from call.answered; only present when callAnalysis was provided
  "metadata": { "externalSessionId": "crm-call-abc123", "campaign": "renewal-2026" },
  "answeredAt": "2026-04-24T10:00:04.500Z",
  "completedAt": "2026-04-24T10:02:22.000Z"
}
```

***

## Webhook Security

Webhook payloads can be verified using HMAC-SHA256 signing.

#### Request Header

HTTP1X-Signature: sha256=\<hex>Show more lines

#### Signature Generation

Plain Text1HMAC-SHA256(webhookAuth, rawRequestBody)Show more lines

#### Best Practices

* Always provide a strong `webhookAuth`
* Validate every callback signature
* Use HTTPS only
* Implement endpoint-level security
* Use IP allowlisting when possible

***

## Interaction Examples

### Example 1: Poll Mode – Customer Renewal Call

An external CRM triggers a call to a customer, then polls for the outcome.

```
Step 1: Trigger the call
POST /cgw/outbound/v1/orgs/3f6a1b2c-8e4d-4f9a-b7c5-1a2b3c4d5e6f/flows/a1b2c3d4-e5f6-7890-abcd-ef1234567890/calls
Authorization: Bearer ce598795-befb-849c-ca52-ed50c7e42e6a

{
  "destinationNumber": "+15551234567",
  "mode": "poll",
  "variables": { "customerName": "Jane Doe", "policyNumber": "POL-998877" },
  "callAnalysis": ["live_person"],
  "metadata": { "externalSessionId": "crm-task-54321" }
}

← 201 Created
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "Queued",
  "createdAt": "2026-04-24T10:00:00.000Z"
}

Step 2: Poll after a few seconds — call is ringing
GET /cgw/outbound/v1/orgs/3f6a1b2c-8e4d-4f9a-b7c5-1a2b3c4d5e6f/calls/6e16376b-fd09-4a9a-a49a-9ba4c3901563

← 200 OK
{ "sessionId": "6e16376b-...", "status": "Ringing", ... }

Step 3: Poll again — call was answered and AMD ran
← 200 OK
{ "sessionId": "6e16376b-...", "status": "Answered", "callAnalysisResult": "live_person", "answeredAt": "2026-04-24T10:00:06.200Z", ... }

Step 4: Poll again — call completed
← 200 OK
{
  "sessionId": "6e16376b-fd09-4a9a-a49a-9ba4c3901563",
  "flowId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "Completed",
  "durationSeconds": 187,
  "callAnalysisResult": "live_person",
  "metadata": { "externalSessionId": "crm-task-54321" },
  "answeredAt": "2026-04-24T10:00:06.200Z",
  "completedAt": "2026-04-24T10:03:13.700Z"
}
```

#### Step 1: Create the Call

HTTP1POST /cgw/outbound/v1/orgs/{orgId}/flows/{flowId}/callsShow more linesJSON1{2"destinationNumber": "+15551234567",3"mode": "poll",4"variables": {5"customerName": "Jane Doe",6"policyNumber": "POL-998877"7},8"callAnalysis": \["live\_person"],9"metadata": {10"externalSessionId": "crm-task-54321"11}12}Show more lines

Response:

#### Step 2: Poll Call Status

JSON1{2"status": "Ringing"3}Show more lines

#### Step 3: Call Answered

JSON1{2"status": "Answered",3"callAnalysisResult": "live\_person"4}Show more lines

#### Step 4: Call Completed

JSON1{2"status": "Completed",3"durationSeconds": 1874}Show more lines

***

### Example 2: Webhook Mode – Demo Platform Integration

The iX Demos platform triggers a call and receives callbacks at each lifecycle event.

```
Step 1: Trigger the call with webhook mode
POST /cgw/outbound/v1/orgs/9c7e2f1a-3b4d-4e8f-a6c2-7d8e9f0a1b2c/flows/b2c3d4e5-f6a7-8901-bcde-f12345678901/calls
Authorization: Bearer ...

{
  "destinationNumber": "+447700900123",
  "mode": "webhook",
  "variables": { "passengerName": "Alex Smith", "flightCode": "CX402" },
  "callAnalysis": ["live_person"],
  "webhookUrl": "https://demos.ixhello.com/callbacks/call-complete",
  "metadata": { "externalSessionId": "demo-session-88" }
}

← 201 Created
{
  "sessionId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "flowId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "status": "Queued",
  "createdAt": "2026-04-24T11:00:00.000Z"
}

Step 2: Recipient answers — AMD runs — platform fires call.answered callback
POST https://demos.ixhello.com/callbacks/call-complete
X-Signature: sha256=1a2b3c...

{
  "event": "call.answered",
  "sessionId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "flowId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "status": "Answered",
  "callAnalysisResult": "live_person",
  "metadata": { "externalSessionId": "demo-session-88" },
  "answeredAt": "2026-04-24T11:00:06.300Z"
}

Step 3: Flow completes — platform fires call.completed callback
POST https://demos.ixhello.com/callbacks/call-complete
X-Signature: sha256=4d5e6f...

{
  "event": "call.completed",
  "sessionId": "8c996034-eeff-4efc-b04e-4fb410d6f2b0",
  "flowId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "status": "Completed",
  "durationSeconds": 94,
  "callAnalysisResult": "live_person",
  "metadata": { "externalSessionId": "demo-session-88" },
  "answeredAt": "2026-04-24T11:00:06.300Z",
  "completedAt": "2026-04-24T11:01:40.300Z"
}
```

***

### Example 3: Sync Mode – Short Demo Flow

A simple demo scenario where the caller can afford to wait for the result.

```
Trigger call — connection stays open
POST /cgw/outbound/v1/orgs/9c7e2f1a-3b4d-4e8f-a6c2-7d8e9f0a1b2c/flows/c3d4e5f6-a7b8-9012-cdef-123456789012/calls

{ "destinationNumber": "+15559876543", "mode": "sync" }

... connection held open while call runs ...

← 200 OK  (after 47 seconds)
{
  "sessionId": "d4e5f6a7-b8c9-0123-defa-234567890123",
  "flowId": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "status": "Completed",
  "durationSeconds": 47,
  "completedAt": "2026-04-24T14:05:47.000Z"
}
```

#### Request

JSON1{2"destinationNumber": "+15559876543",3"mode": "sync"4}Show more lines

#### Response

JSON1{2"status": "Completed",3"durationSeconds": 474}Show more lines

***

### Example 4: Answering Machine Detected

AMD is enabled. The flow receives `answering_machine` as a session variable and plays a voicemail prompt before hanging up.

```
POST /cgw/outbound/v1/orgs/3f6a1b2c-8e4d-4f9a-b7c5-1a2b3c4d5e6f/flows/e5f6a7b8-c9d0-1234-efab-345678901234/calls

{
  "destinationNumber": "+15551112222",
  "mode": "poll",
  "callAnalysis": ["live_person", "answering_machine"],
  "variables": { "customerName": "Bob Jones" }
}

← 201 Created
{
  "sessionId": "f6a7b8c9-d0e1-2345-fabc-456789012345",
  "flowId": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "status": "Queued"
}

Call answered by answering machine → AMD fires → flow starts with callAnalysisResult: "answering_machine"
Flow branches: plays voicemail message → hangs up

GET /cgw/outbound/v1/orgs/3f6a1b2c-8e4d-4f9a-b7c5-1a2b3c4d5e6f/calls/f6a7b8c9-d0e1-2345-fabc-456789012345
← 200 OK
{
  "sessionId": "f6a7b8c9-d0e1-2345-fabc-456789012345",
  "flowId": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "status": "Completed",
  "durationSeconds": 18,
  "callAnalysisResult": "answering_machine",
  "completedAt": "2026-04-24T10:05:18.000Z"
```

***

## Error Responses

All API errors follow a common format.

JSON1{2"error": {3"code": "ERROR\_CODE",4"message": "Human-readable description"5}6}Show more lines

| HTTP Status | Code                  | Description                   |
| ----------- | --------------------- | ----------------------------- |
| 400         | INVALID\_REQUEST      | Invalid request payload       |
| 400         | INVALID\_DESTINATION  | Invalid PSTN/SIP destination  |
| 400         | INVALID\_WEBHOOK\_URL | Invalid webhook configuration |
| 401         | AUTH\_HEADER\_MISSING | Missing authorization header  |
| 401         | INVALID\_TOKEN        | Invalid API key               |
| 403         | PERMISSION\_DENIED    | Access denied                 |
| 404         | NOT\_FOUND            | Session not found             |
| 429         | RATE\_LIMIT\_EXCEEDED | Request limit exceeded        |
| 504         | SYNC\_TIMEOUT         | Sync request exceeded timeout |

***

## Summary

The **Outbound Calling API** provides a secure, scalable, and flexible mechanism for initiating outbound voice conversations and executing conversational AI flows. With support for PSTN and SIP dialing, session variable injection, Answering Machine Detection (AMD), Sync/Poll/Webhook execution modes, status tracking, and webhook-based event notifications, organizations can build proactive customer engagement experiences, automated workflows, testing frameworks, and enterprise-grade voice integrations using a single API.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.ixhello.com/ixhc2/integrations/outbound-calling-api-user-guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
