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

# Vodex API

> The REST API your systems integrate with — assistants, telephony, calls, batches, SMS and webhooks

<CardGroup cols={3}>
  <Card title="Place calls" icon="phone" href="/quickstart">
    One POST puts an AI agent on the phone. It returns when the INVITE is on its
    way, not when someone answers.
  </Card>

  <Card title="Get the report back" icon="webhook" href="/webhooks">
    Every finished interaction is POSTed to your endpoint, signed and complete —
    no follow-up GET.
  </Card>

  <Card title="One key, one customer" icon="key" href="/authentication">
    A `vdx_live_` key carries its own tenant. There is no tenant parameter to
    get wrong.
  </Card>
</CardGroup>

<Note>Base URL: `https://apiv2.vodex.ai/v1`</Note>

## What this covers

Everything a customer's own systems integrate with: assistants, telephony
(numbers, trunks, carrier integrations), calls and recordings, batch dialing,
the SMS channel, and outbound webhooks.

It is deliberately a subset. Account and console-only routes, platform
provisioning, Vodex support operations, and the endpoints other systems call
inward (carrier delivery receipts, the agent worker, cron) are not part of the
published surface.

The **data plane** — the LiveKit SFU, SIP, and the agent worker — is not an HTTP
API and is not described here. A call reaches the worker over LiveKit, with its
config carried in participant metadata or read from the config snapshot this API
publishes.

## Response shapes

Resources come back **flat**, at the top level — there is no envelope object.
Collections vary by the age of the endpoint:

* Newer lists are `{ "<plural>": [ … ], "total": n, "limit": n, "offset": n }` —
  `calls`, `batches`, `rows`, `attempts`, `messages`.
* Older lists return a **bare JSON array**: `/phone-numbers`, `/sip-trunks`,
  `/integrations`, `/carriers`, `/console/assistants`, `/sms/configurations`.

Deletes and side-effecting no-content operations return `{ "ok": true }`.

## Errors

```json theme={null}
{ "error": "human-readable message" }
```

A flat string, not a coded object — the HTTP status is the machine signal. The
one exception is quota exhaustion (`402`), which adds a stable
`code: "quota_exhausted"` plus the counters the console renders.

## Pagination

`?limit=` and `?offset=`, with `total` in the body. Defaults and ceilings differ
per endpoint (calls 25/100, batch rows 50/500, attempts 100/500) and are stated
on each operation.

## Conventions

|                   |                                                                                                                                                                                                                             |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Phone numbers** | E.164 strings (`+14155551234`). `+91…` numbers are served from Mumbai, `+1…` from us-central1.                                                                                                                              |
| **Money**         | A JSON number of USD (`costUsd`), not a decimal string.                                                                                                                                                                     |
| **Timestamps**    | ISO-8601 UTC strings — except the calls list, which reports `mtime` / `startedAt` as epoch **milliseconds** and durations in milliseconds.                                                                                  |
| **Ids**           | Unprefixed. Batches, rows, attempts and SMS rows are UUIDs; a call id is its LiveKit room name (`call-…`, or `console-…` for web calls); a phone number's id is `num-<digits>`; a trunk's is `trunk-…`.                     |
| **Secrets**       | `vdx_live_…` and `whsec_…` are returned exactly once, by the call that mints them. No endpoint reads one back. Carrier and provider credentials live in Secret Manager and are echoed only as a non-reversible fingerprint. |
| **Idempotency**   | `POST /sms` and `POST /batches` **require** an `Idempotency-Key`. Only successful (2xx) responses are replayed; a failed attempt releases the key so a corrected retry can reuse it.                                        |

## Customers, tenants and workspaces

Three words, and they are not interchangeable.

**Customer** is the product word — what a human calls the account, and what the
console shows. **Tenant** is the same thing's identity on the wire and in
storage: `tenantId` on every response.

**A workspace is a third thing, and not a synonym for either.** Tenancy is
mapped at the customer level deliberately: integrations (carrier, SMS, provider
credentials) live above the workspaces that use them, so mapping workspaces to
tenants would fragment one customer's telephony across tenants that then have to
share credentials. A workspace is therefore a **label inside the tenant**
(`externalWorkspaceRef`) — for filtering and attribution, never isolation.

<Warning>
  Anything that must not be shared between one customer's workspaces needs its own
  tenant.
</Warning>
