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

# Public API overview

> Sync CRM data and run AI Voice Agents with a Custom Integration API key

The Ringee **Public API** uses **Custom Integrations** to let an external system sync contacts and companies, receive call activity, open a secure dialer and run AI Voice Agents.

CRM synchronization is bidirectional and event-based. AI Voice Agent execution uses resource-oriented endpoints that return call ids for asynchronous result polling.

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/api/authentication">
    Create an integration and get your `cik_live_` API key
  </Card>

  <Card title="AI Voice Agents" icon="robot" href="/voice-agents/api-reference">
    List agents, start calls and read structured results
  </Card>

  <Card title="Build an integration" icon="wrench" href="/api/build-an-integration">
    End-to-end guide with idempotency, retries and loop prevention
  </Card>
</CardGroup>

## What you can do

| Capability | Direction | Endpoint |
| - | - | - |
| Create and update contacts and companies | CRM → Ringee | `POST /api/integrations/custom/webhook` |
| Archive deleted contacts and companies | CRM → Ringee | `POST /api/integrations/custom/webhook` |
| Open a secure dialer for a contact | CRM → Ringee | `POST /api/integrations/custom/click-to-call` |
| List configured AI Voice Agents | App → Ringee | `GET /api/v1/ai-voice-agents` |
| Start an autonomous AI voice call | App → Ringee | `POST /api/v1/ai-voice-agents/:id/calls` |
| Read AI voice call results | App → Ringee | `GET /api/v1/ai-voice-agents/calls/:callId` |
| Receive completed, missed and failed calls | Ringee → App | Your webhook URL |
| Receive outcomes, notes, callbacks, meetings | Ringee → App | Your webhook URL |
| Receive recordings and Do Not Call entries | Ringee → App | Your webhook URL |

## How it works

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
flowchart LR;
    classDef crm fill:#22C55E,color:white,stroke:#fff
    classDef ringee fill:#15803D,color:white,stroke:#fff

    crm[Your CRM]:::crm
    ringee[Ringee]:::ringee

    crm -- "POST /webhook (X-Ringee-Api-Key)" --> ringee
    crm -- "POST /click-to-call" --> ringee
    crm -- "POST /v1/ai-voice-agents/:id/calls" --> ringee
    ringee -- "signed webhook (Ringee-Signature)" --> crm
```

* **Inbound** (CRM → Ringee): you send events to a single Ringee endpoint, authenticated with your secret API key. See [Inbound events](/api/inbound-events).
* **Outbound** (Ringee → CRM): Ringee sends HMAC-signed events to the URL you configure, with automatic retries. See [Outbound webhooks](/api/outbound-webhooks).
* **Click-to-call**: you exchange a contact for a short-lived, signed dialer URL your agent opens in the browser. See [Click-to-call](/api/click-to-call).
* **AI Voice Agents**: your server lists configured agents, starts calls and polls normalized results. See [AI Voice Agents API](/voice-agents/api-reference).

## The event envelope

Every event in both directions shares the same envelope:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "event": "contact.upserted",
  "eventId": "crm_01HX5Z7K8MZP1Q4V0G9YJ2RH3T",
  "occurredAt": "2026-05-23T14:30:00.000Z",
  "data": {}
}
```

Outbound events (Ringee → your application) add two fields:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "workspaceId": "org_2k7yX...",
  "integrationId": "ci_..."
}
```

They can also add shared source fields under `data`:

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "user": {
    "id": "usr_…",
    "email": "ada@babbage.example.com",
    "fullName": "Ada Lovelace"
  },
  "agent": { "id": "va_…", "name": "Sofia" },
  "externalId": "crm-contact-42"
}
```

`data.user` identifies the Ringee user the event belongs to. `data.agent` is
present when an AI Voice Agent produced the event. If you start that call with
`metadata.external_id` or `metadata.externalId`, Ringee copies it to
`data.externalId` on every related outbound event.

<Note>
  `eventId` must identify one logical event and remain stable across transport
  retries. If Ringee returns `status: "failed"` while processing an inbound
  event, fix the payload and use a **new** `eventId`; the original id is already
  recorded.
</Note>

## Choosing the right integration surface

Ringee exposes several ways to build on top of it. They solve different problems and can be combined.

<CardGroup cols={2}>
  <Card title="Public API" icon="webhook" href="/api/overview">
    **Server to server.** Sync CRM records and receive call activity. Requires a
    backend.
  </Card>

  <Card title="Dialer SDK" icon="phone" href="/dialer-sdk/overview">
    **Browser.** Embed a real dialer in your own web app. No backend required.
  </Card>

  <Card title="MCP" icon="robot" href="/mcp/overview">
    **AI agents.** Let Claude or ChatGPT operate Ringee on the user's behalf.
  </Card>

  <Card title="AI Voice Agents" icon="robot" href="/voice-agents/overview">
    **Autonomous calls.** Place server-originated conversations and read
    structured results.
  </Card>
</CardGroup>

A typical CRM integration uses **both** the Public API (to sync data and log activity) and either **click-to-call** or the **Dialer SDK** (to actually place calls from the CRM UI).

<Note>
  Every inbound, click-to-call and AI Voice Agent request uses the Custom
  Integration `cik_live_…` key. AI Voice Agent endpoints also accept that same
  key as a Bearer credential.
</Note>

## Base URL

| Deployment | Base URL |
| - | - |
| Hosted | `https://api.ringee.io` |
| Self-hosted | Your `BACKEND_URL` (see [Configuration reference](/configuration/reference)) |

All endpoints in this section are relative to that base URL and live under the global `/api` prefix.

## Limits and expectations

* Ringee considers an outbound delivery failed if your endpoint does not respond within **15 seconds** or returns a non-2xx status.
* Failed deliveries are retried up to **10 times** with exponential backoff, capped at **5 minutes** between attempts.
* Outbound deliveries are independent and can arrive out of order. Use
  `eventId` for idempotency and `data.callId` for call-level correlation.
* Event payloads can gain optional fields over time. Ignore unknown keys and validate the fields your integration actually needs.
* Ringee currently emits **terminal** call events only. There are no `call.started`, `call.ringing` or `call.answered` events — do not build a real-time incoming-call screen on top of this API.

## Next steps

<CardGroup cols={2}>
  <Card title="Create your API key" icon="key" href="/api/authentication">
    Set up a Custom Integration in the dashboard
  </Card>

  <Card title="Event reference" icon="list" href="/api/events-reference">
    Every outbound payload, field by field
  </Card>
</CardGroup>


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