# REST API overview

> Base URL, request and response conventions, the OpenAPI spec, and every endpoint on one page.

Source: https://dev.ody.co/api/overview

The Ody REST API is a JSON-over-HTTPS API rooted at `https://api.ody.co/v1/api`. It uses standard HTTP verbs, returns standard status codes, authenticates with a Bearer [API key](https://dev.ody.co/get-started/authentication), and is described by a machine-readable OpenAPI 3.1 document.

## Base URL

```text
https://api.ody.co/v1/api
```

Every path in this reference is relative to that base. All traffic is HTTPS-only.

## Conventions

| Topic | Rule |
|---|---|
| Format | Request and response bodies are JSON (`Content-Type: application/json`). A body that isn't valid JSON returns `400 invalid_argument` |
| Auth | `Authorization: Bearer ody_live_…` or `ody_test_…` on every request — see [Authentication](https://dev.ody.co/get-started/authentication) |
| Partial updates | `PATCH` changes only the fields you send. Array fields (`phones`, `emails`, `tags`, `notes`, agent `jobs`) are **replaced wholesale** when supplied |
| IDs | UUIDs. A malformed ID returns `404 not_found`, the same as an unknown one |
| Phone numbers | E.164 (`+15125550123`). Encode `+` as `%2B` in paths |
| Lists | Some lists paginate with opaque cursors — see [Pagination](https://dev.ody.co/api/pagination) |
| Retries | `POST /messages` and `POST /numbers` accept an `Idempotency-Key` — see [Idempotency](https://dev.ody.co/api/idempotency) |
| Errors | One envelope: `{ "error": { "code", "message", "requestId" } }` — see [Errors](https://dev.ody.co/api/errors) |
| Limits | 600 requests per minute per key — see [Rate limits](https://dev.ody.co/api/rate-limits) |
| Tracing | Every response carries `X-Request-Id` |
| CORS | Any origin is allowed (keys, not cookies, authenticate) |

## OpenAPI specification

The full contract is served without authentication:

```bash
curl https://api.ody.co/v1/api/openapi.json
```

Import it into Postman, Insomnia or Bruno, or generate a typed client in any language. The [official SDKs](https://dev.ody.co/sdks/overview) are built against it.

## Endpoints

| Method & path | What it does | Scope |
|---|---|---|
| [`GET /contacts`](https://dev.ody.co/api/contacts#list-contacts) | List or search contacts | `contacts:read` |
| [`POST /contacts`](https://dev.ody.co/api/contacts#create-a-contact) | Create a contact | `contacts:write` |
| [`GET /contacts/:id`](https://dev.ody.co/api/contacts#retrieve-a-contact) | Retrieve a contact | `contacts:read` |
| [`PATCH /contacts/:id`](https://dev.ody.co/api/contacts#update-a-contact) | Update a contact | `contacts:write` |
| [`DELETE /contacts/:id`](https://dev.ody.co/api/contacts#delete-a-contact) | Delete a contact | `contacts:write` |
| [`GET /conversations`](https://dev.ody.co/api/conversations#list-conversations) | List conversations | `conversations:read` |
| [`GET /conversations/:id`](https://dev.ody.co/api/conversations#retrieve-a-conversation) | Retrieve a full thread | `conversations:read` |
| [`PATCH /conversations/:id`](https://dev.ody.co/api/conversations#update-a-conversation) | Mark open or done | `conversations:write` |
| [`POST /messages`](https://dev.ody.co/api/messages#send-a-message) | Send SMS/MMS | `messages:send` |
| [`GET /messages/search`](https://dev.ody.co/api/messages#search-messages) | Search message bodies and transcripts | `conversations:read` |
| [`GET /calls`](https://dev.ody.co/api/calls#list-calls) | Call and voicemail history | `conversations:read` |
| [`POST /calls`](https://dev.ody.co/api/calls#place-an-ai-call) | Place an outbound AI call | `calls:place` |
| [`GET /numbers`](https://dev.ody.co/api/numbers#list-numbers) | List workspace numbers | `numbers:read` |
| [`GET /numbers/available`](https://dev.ody.co/api/numbers#search-available-numbers) | Search numbers you can buy | `numbers:manage` |
| [`POST /numbers`](https://dev.ody.co/api/numbers#buy-a-number) | Buy a number | `numbers:manage` |
| [`POST /numbers/:e164/connect`](https://dev.ody.co/api/numbers#route-a-number-to-the-agent) | Route a number to Astra | `agent:manage` |
| [`POST /numbers/:e164/disconnect`](https://dev.ody.co/api/numbers#route-a-number-away-from-the-agent) | Route a number away from Astra | `agent:manage` |
| [`GET /messaging`](https://dev.ody.co/api/messaging#retrieve-registration-status) | 10DLC status | `numbers:manage` |
| [`POST /messaging/registration`](https://dev.ody.co/api/messaging#submit-a-registration) | File 10DLC brand + campaign | `numbers:manage` |
| [`POST /messaging/refresh`](https://dev.ody.co/api/messaging#refresh-status) | Re-check 10DLC status | `numbers:manage` |
| [`POST /messaging/otp/verify`](https://dev.ody.co/api/messaging#verify-a-sole-proprietor-pin) | Sole proprietor: submit PIN | `numbers:manage` |
| [`POST /messaging/otp/resend`](https://dev.ody.co/api/messaging#resend-a-sole-proprietor-pin) | Sole proprietor: resend PIN | `numbers:manage` |
| [`GET /agent`](https://dev.ody.co/api/agent#retrieve-the-agent) | Astra config + credit usage | `agent:manage` |
| [`PATCH /agent`](https://dev.ody.co/api/agent#update-the-agent) | Create or update the draft | `agent:manage` |
| [`POST /agent/publish`](https://dev.ody.co/api/agent#publish-the-agent) | Push the config live | `agent:manage` |
| [`GET /webhook-events`](https://dev.ody.co/api/webhook-endpoints#list-event-types) | Subscribable event types | `webhooks:manage` |
| [`GET /webhooks`](https://dev.ody.co/api/webhook-endpoints#list-endpoints) | List endpoints | `webhooks:manage` |
| [`POST /webhooks`](https://dev.ody.co/api/webhook-endpoints#create-an-endpoint) | Register an endpoint | `webhooks:manage` |
| [`GET /webhooks/:id`](https://dev.ody.co/api/webhook-endpoints#retrieve-an-endpoint) | Retrieve an endpoint | `webhooks:manage` |
| [`PATCH /webhooks/:id`](https://dev.ody.co/api/webhook-endpoints#update-an-endpoint) | Update an endpoint | `webhooks:manage` |
| [`DELETE /webhooks/:id`](https://dev.ody.co/api/webhook-endpoints#delete-an-endpoint) | Delete an endpoint | `webhooks:manage` |
| [`POST /webhooks/:id/rotate`](https://dev.ody.co/api/webhook-endpoints#rotate-the-signing-secret) | Rotate the secret | `webhooks:manage` |
| [`POST /webhooks/:id/test`](https://dev.ody.co/api/webhook-endpoints#send-a-test-delivery) | Send a signed ping | `webhooks:manage` |
| [`GET /webhooks/:id/deliveries`](https://dev.ody.co/api/webhook-endpoints#list-deliveries) | Delivery history | `webhooks:manage` |
| `GET /openapi.json` | The OpenAPI spec | none |
