> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ringg.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> To search or read these docs, connect the Ringg docs MCP server at https://docs.ringg.ai/mcp (no key needed; tools search_ringg_ai and query_docs_filesystem_ringg_ai) instead of browsing pages one by one. Setup for each client: https://docs.ringg.ai/resources/mcp-server/docs-mcp-server/mcp-for-ai-assistants.md
> The dashboard labels agents "Assistants"; these docs say "agent". Both mean the same object, identified by agent_id.
> API base URL: https://prod-api.ringg.ai/ca/api/v0. Send the workspace API key in the X-API-KEY header, from server-side code only.
> Placing a call dials a real phone number and spends credits. Confirm the number with the user before calling.
> To act on a Ringg workspace (place calls, edit agents, read transcripts), use the separate Ringg workspace MCP server at https://mcp.ringg.ai/mcp: https://docs.ringg.ai/resources/mcp-server/workspace-mcp-server/overview.md

# Ozonetel

> Connect an Ozonetel account to Ringg AI, then configure the outbound, inbound and status callback URLs Ozonetel calls for each agent call and its retries.

Ozonetel connects to Ringg over HTTP and WebSocket: Ozonetel dials the customer and calls Ringg's URLs, and Ringg replies with the instruction for each stage of the call ([bring your own telephony](/documentation/inventory/phone-numbers/your-own-telephony/byot-overview)). The three URLs you set in Ozonetel, all accepting GET and POST:

| Purpose | Where you set it | URL |
| - | - | - |
| [**Outbound**](#outbound-url) | The campaign's agent-flow URL | `https://use1-api.ringg.ai/pc/v1/ozonetel/start_call` |
| [**Inbound**](#inbound-url) | The URL node of your inbound flow | `https://use1-api.ringg.ai/pc/v1/ozonetel/inbound_call` |
| [**Status callback**](#status-callback-url) | The campaign's Call-Summary (CDR) push URL | `https://use1-api.ringg.ai/pc/v1/ozonetel/status?call_id=<RINGG_CALL_ID>` |

## Before you start

<Columns cols={2}>
  <Card title="An Ozonetel account" icon="building" horizontal>
    With API access and at least one <Tooltip tip="Direct inward dialing number: a phone number that routes straight to a line or agent.">DID</Tooltip>. Have its API key, campaign name, user name and the <Tooltip tip="Session Initiation Protocol: the standard for connecting voice calls between phone systems.">SIP</Tooltip> extension your campaign streams from.
  </Card>

  <Card title="An agent" icon="bot" href="/documentation/build-agents/agents/create-an-agent" horizontal>
    The Ringg agent that places or takes the calls.
  </Card>
</Columns>

## Connect the account in Ringg

<Steps>
  <Step title="Open the Ozonetel account form">
    Go to **Numbers → Add number**, select **Ozonetel**, and open **Configure provider** (the gear). Select **Add**.
  </Step>

  <Step title="Fill in the fields and save">
    All fields are required.

    | Field | Value |
    | - | - |
    | **Name** | Your label, for example `Ozonetel Sales` |
    | **Campaign Name** | The Ozonetel campaign Ringg places outbound calls through |
    | **User Name** | The user name sent with each call |
    | **API Key** | Your Ozonetel API key |
    | **SIP Number** | The SIP extension your campaign streams from, for example `36667` |

    <Check>"BYOT added successfully." appears and the account is available in the telephony account selector.</Check>
  </Step>

  <Step title="Add your DIDs">
    With the Ozonetel account selected in **Add number**, add each DID. See [Import a number](/documentation/inventory/phone-numbers/buy-or-import-a-number#import-a-number-you-already-own) and [Add a number by hand](/documentation/inventory/phone-numbers/buy-or-import-a-number#add-a-number-by-hand).
  </Step>
</Steps>

## Outbound URL

Set the campaign's agent-flow URL to:

```text theme={null}
https://use1-api.ringg.ai/pc/v1/ozonetel/start_call
```

Ozonetel hits this same URL for each lifecycle event of the call and Ringg replies with the instruction for that stage.

### The `Name` parameter

When Ringg places an outbound call, it passes a `Name` parameter carrying the Ringg call ID. Ozonetel must send the same `Name` back, unchanged, on every callback; that is how Ringg identifies the call. A callback without it is rejected with `400`, and the call never connects.

```text A callback that carries Name theme={null}
https://use1-api.ringg.ai/pc/v1/ozonetel/start_call?Name=<Ringg call ID>&event_start=NewCall&sid=...
```

### Callback parameters

| Parameter | Sent on | Meaning |
| - | - | - |
| `Name` | all events | The Ringg call ID, echoed back unchanged ([above](#the-name-parameter)). |
| `event_start=NewCall` | call answered | Ringg replies with the stream instruction that connects the bot. |
| `sid` | `NewCall` | Ozonetel's call SID. |
| `PhoneNumber` or `cid` | `NewCall` | Customer number. |
| `DID`, `did` or `called_number` | `NewCall` | The DID that was dialed. |
| `event=Stream` | bot leg finished | Ringg replies with hangup, or with a transfer instruction if the agent requested one. |
| `event=Hangup` / `Disconnect` | teardown | Ringg acknowledges. |

Ringg serves the stream instruction once per call, for 10 minutes. A duplicate `NewCall` for the same `Name` gets an empty response instead of a second stream.

## Inbound URL

Point the URL node of your inbound flow at:

```text theme={null}
https://use1-api.ringg.ai/pc/v1/ozonetel/inbound_call
```

Ringg's team shares the exact inbound URL for your agent; configure it as given, without editing the query string.

| Parameter | Sent on | Meaning |
| - | - | - |
| `event_start=NewCall` | call arrives | Ringg registers the call and replies with the stream instruction. |
| `sid` | `NewCall` | Ozonetel's call SID. Required: it identifies the call for its whole lifetime. |
| `cid` (or `PhoneNumber`) | `NewCall` | Caller's number. |
| `did`, `DID` or `called_number` | `NewCall` | The DID that was called. |
| `event=Hangup` / `Disconnect` | teardown | Ringg marks the call completed. |
| `event=Stream` | bot leg finished | Ringg replies with hangup so the flow tears down. |

Ringg answers with a hangup instruction when `sid` is missing, the agent cannot be resolved, or the SIP extension is not configured.

## Status callback URL

Set the campaign's Call-Summary (CDR) push URL to:

```text theme={null}
https://use1-api.ringg.ai/pc/v1/ozonetel/status?call_id=<RINGG_CALL_ID>
```

This callback drives Ringg's retry and failure handling: without it, unanswered and busy calls are not retried. Ringg reads the parameters from the POST body (JSON or `x-www-form-urlencoded`) when there is one, otherwise from the query string, and unwraps a `data=<json-string>` envelope.

### Identifying the call

* **Outbound**: template the Ringg call ID into the URL as `call_id`, or make sure `Name` is present in the push. If neither is there, the push is ignored.
* **Inbound**: Ringg uses Ozonetel's own call ID: `monitorUCID`, `ucid`, or `sid`.
* Direction comes from `Type` (or `call_type` / `direction`). Only `Inbound` counts as inbound; `Manual`, `Preview`, `Progressive`, `Predictive`, `IVR` and an absent value are treated as outbound.

### Call disposition

Send the call disposition in `CustomerStatus`, `DialStatus`, `Status` or `AgentStatus`. Ringg reads whichever is present, most granular first.

The endpoint always returns `200 {"status": "ok"}` so Ozonetel does not retry the push.

## Troubleshooting

| Symptom | Likely cause |
| - | - |
| Outbound returns `400 Missing call identifier` | The campaign is not echoing `Name` back on the callback. |
| Outbound returns `400 Runtime config not found` | The callback arrived long after dial-out, or `Name` carries a different value than the call ID Ringg sent. |
| Inbound answers and immediately hangs up | **SIP Number** missing on the Ringg Ozonetel account, missing `sid`, or the inbound URL was edited instead of used as given. |
| Call connects but there is no audio | Outbound WebSocket traffic to `use1-api.ringg.ai` is blocked from your network. |
| Unanswered calls are never retried | The status callback is not configured, or it does not carry `call_id`/`Name` for outbound. |
| Second `NewCall` gets an empty response | Expected: the stream instruction is [served once per call](#callback-parameters). |

## Next steps

<Columns cols={2}>
  <Card title="Attach a number to an agent" icon="phone-incoming" href="/documentation/inventory/phone-numbers/inbound-agent-number">
    Answer inbound calls on an Ozonetel DID.
  </Card>

  <Card title="Run a campaign" icon="megaphone" href="/documentation/deploy/campaigns/create-a-campaign">
    Place outbound calls through Ozonetel.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.