> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.agentphone.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.agentphone.ai/_mcp/server.

# Authentication

> Create an API key, choose the account scope, and distinguish API, webhook, and browser-call credentials.

Create an API key in [Settings](https://agentphone.ai/settings). Keep it on your server and send it in the `Authorization` header:

```bash
export AGENTPHONE_API_KEY="YOUR_API_KEY"
curl --fail-with-body "https://api.agentphone.ai/v1/agents?limit=1" \
  -H "Authorization: Bearer $AGENTPHONE_API_KEY"
```

A successful response contains `data` and `total`. An empty `data` array is normal before you create an agent. A `401` means authentication failed; check the key and header before creating resources.

## Base URL and field names

The API origin is `https://api.agentphone.ai`. Most public resources use `/v1`, but WhatsApp connection and template endpoints use `/integrations/whatsapp`. Use the complete path in the API reference. The SDKs' default base URL is the origin, without `/v1`.

Request naming varies by endpoint: number creation uses `agentId`, message sending uses `agent_id`, and call creation uses `agentId`. Copy the field names from the endpoint schema; they are not interchangeable. The Python SDK exposes Python-style names and translates them for you.

## Account scope

An API key targets its owning account by default. To operate in a sub-account, send the parent's key with `X-Sub-Account-Id` on **every** request in the workflow:

```bash
curl --fail-with-body "https://api.agentphone.ai/v1/numbers" \
  -H "Authorization: Bearer $AGENTPHONE_API_KEY" \
  -H "X-Sub-Account-Id: YOUR_SUB_ACCOUNT_ID"
```

Agents, numbers, registration, conversations, and webhook configuration must be in the same scope. An ID returned under one account is not automatically accessible in another. A `404` can mean the resource exists in a different scope. See [Sub-accounts](/sub-accounts) for working SDK and HTTP examples.

## Different secrets have different jobs

| Credential             | Purpose                                | Where to use it                                                                                  |
| ---------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------ |
| API key                | Authorize API requests                 | Server-side `Authorization: Bearer …`; also accepted by the hosted MCP server.                   |
| Webhook signing secret | Verify events received from AgentPhone | Your webhook handler; returned when configuring that webhook. This is not your API key.          |
| Web-call access token  | Start one browser voice session        | Mint on your backend using `POST /v1/calls/web`, then pass the short-lived token to the web SDK. |

Use the exact raw request bytes for [webhook verification](/documentation/guides/webhooks#security). Saving a webhook can change its secret: update your handler with the secret returned by that save.

Most API endpoints require the bearer header. Recording URLs and some media URLs are bearer links: possession of the URL grants access. Treat those links as sensitive, and see [Call recording](/documentation/guides/calls#call-recording).

## SDKs and MCP

* [TypeScript](/documentation/sdks/typescript): `new AgentPhoneClient({ token: process.env.AGENTPHONE_API_KEY, maxRetries: 0 })`.
* [Python](/documentation/sdks/python): `AgentPhone(api_key=os.environ["AGENTPHONE_API_KEY"])`.
* [Hosted MCP](/mcp): browser sign-in where supported, or the bearer header.
* [Local MCP](/mcp#local-server-npm): set `AGENTPHONE_API_KEY` in the server process's environment.

Use separate credentials for your application environments. Sub-accounts isolate resources, but share the parent's balance; they are not a free sandbox.