# Avox API Authentication

> How Avox API keys work: named live (avx_live_) and test (avx_test_) keys for one WhatsApp number, the Authorization header, emailed codes for creating, rotating and revoking, rotation that keeps limits, and keeping keys safe.

Source: https://docs.theavoxai.com/avox-api/authentication

Every request to the [Avox API](https://docs.theavoxai.com/avox-api) is authenticated with an **Avox API key** sent in the
`Authorization` header. There's nothing else to set up - no OAuth, no signing, no Meta token.

## What a key is

- A key starts with a prefix that says what it does, followed by a long random string:

| Prefix | Kind | What a send does |
| --- | --- | --- |
| `avx_live_` | Live key | Sends a real WhatsApp message. |
| `avx_test_` | Test key | Runs every check, then answers with a pretend result (`"test": true`, `Avox-Test-Mode: true`). Never sends. See [Testing](https://docs.theavoxai.com/avox-api/testing#1-test-mode). |

- Each key belongs to **one connection** - one WhatsApp number in one Switchboard. You pick the
  number when you create the key, and it can only ever send from that number.
- Each key has a **name** (2 to 60 characters, unique among the Switchboard's working keys) and an
  optional description, so the dashboard, the API logs and any security warning say exactly which key
  and which system it is. It also records who created it and when.
- A connection can have several active keys at once, which is how you rotate keys without
  downtime.
- The full key is shown exactly once, when it's created or rotated. After that the dashboard only
  shows its first few characters (for example `avx_live_8f2a…`) so you can tell keys apart.
- Your code can tell the two kinds apart by the prefix, and every response from a test key carries
  the `Avox-Test-Mode: true` header.

## Getting a key

Admins - and Managers an Admin has given **Manage API keys** - can create, rotate or revoke keys.
Each of those three actions also needs a **6-digit code emailed to the person doing it**: it works
once, for 10 minutes, only for that one action on that one key (or number), and stops working after 5
wrong tries. See [Confirmation codes](https://docs.theavoxai.com/connections/api-keys#confirmation-codes).

**1. Step 1**

API Keys and click Create a key">
   This tab lists every key across every connection in the Switchboard. You can also use **Create a
   key for this number** in the **Outbound API keys** section on a connection's own page.

**2. Pick the Switchboard and the WhatsApp number**

The Switchboard you're in is picked to start with. If it has more than one number, choose one -
each shows its name, the number partly hidden, and its status. Avox never guesses the number. If
you have no connected number yet, the tab shows "Connect a WhatsApp number first - a key always
sends from one number."

**3. Choose Live key or Test key, and name the key**

**Live key** "Sends real WhatsApp messages from this number"; **Test key** "Never sends anything".
The **Key name** is suggested for you (for example "Sales line live key"); add **What it's for** if
you like.

**4. Click Email me a code, and type the code**

The key is created as soon as the last digit is in, and **Your new API key** opens with the full
key and a copy button.

**5. Copy it, then click Done**

This is the only time the full key is shown. If you close the dialog without copying it,
rotate that key (or revoke it and create another).

The step-by-step guide with every button on both screens is on [API keys](https://docs.theavoxai.com/connections/api-keys).

> **Note**
>
> API access depends on your plan. On a plan without it, both screens read "API access isn't
> included in your plan" in place of the create form, with a link to the plans that include it. Your
> keys stay listed, but new keys can't be created or rotated, and existing keys stop sending with
> [`api_not_in_plan`](https://docs.theavoxai.com/api/errors#api_not_in_plan) until your plan includes API access again. A
> paused plan has no API access either. See
> [API access and your plan](https://docs.theavoxai.com/connections/api-keys#api-access-and-your-plan).

> **Note**
>
> If API keys are switched off for your account, both screens say so in place of the create form
> ("API keys have been turned off for your account"). Existing keys stop sending too, with
> [`api_access_disabled`](https://docs.theavoxai.com/api/errors#api_access_disabled). Contact [Support](https://docs.theavoxai.com/support) if you
> need them.

## Sending the key

Put the key in the `Authorization` header with the `Bearer` scheme, on every request:

```
Authorization: Bearer avx_live_your_key_here
```

**curl**

```bash
curl -X POST https://api.avox.com/api/messages/send \
  -H "Authorization: Bearer $AVOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"15551234567","type":"text","text":{"body":"Hi!"}}'
```

**Node.js**

```js
const res = await fetch("https://api.avox.com/api/messages/send", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AVOX_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ to: "15551234567", type: "text", text: { body: "Hi!" } }),
});
```

**Python**

```python
import os

import requests

res = requests.post(
    "https://api.avox.com/api/messages/send",
    headers={"Authorization": f"Bearer {os.environ['AVOX_API_KEY']}"},
    json={"to": "15551234567", "type": "text", "text": {"body": "Hi!"}},
    timeout=30,
)
```

- The word `Bearer` can be any case, followed by one or more spaces and the key.
- Send the key exactly as it was shown - no quotes, no line breaks, nothing cut off.
- Dashboard sign-ins don't work on this endpoint, and an API key can't sign in to the dashboard.
  The two are kept fully separate.

## Scoping: one key, one number

A key carries its connection with it. That's why the URL has no phone number id, and why nothing
in the request body can point a send at a different number or a different account.

- To send from two numbers, create one key per number and pick the key by number in your code.
- If the number is paused, every key for it gets
  [`connection_paused`](https://docs.theavoxai.com/api/errors#connection_paused) until it's resumed.
- If the number is deleted, its keys get
  [`connection_not_found`](https://docs.theavoxai.com/api/errors#connection_not_found).
- If the number needs reconnecting on Meta's side, its keys get
  [`connection_not_ready`](https://docs.theavoxai.com/api/errors#connection_not_ready).

Use **Test** in **Settings > API Keys** to see which number a key sends from - a working key shows
"Working - routes to" followed by the connection's name.

## Authentication errors

| Code | Status | What it means |
| --- | --- | --- |
| [`missing_api_key`](https://docs.theavoxai.com/api/errors#missing_api_key) | `401` | No `Authorization` header was sent. |
| [`invalid_api_key`](https://docs.theavoxai.com/api/errors#invalid_api_key) | `401` | The header isn't `Bearer <key>`, or the key isn't one Avox recognises. |
| [`key_revoked`](https://docs.theavoxai.com/api/errors#key_revoked) | `401` | The key was revoked. |
| [`key_expired`](https://docs.theavoxai.com/api/errors#key_expired) | `401` | The key was rotated and its grace period has ended. Use the key that replaced it. |
| [`ip_not_allowed`](https://docs.theavoxai.com/api/errors#ip_not_allowed) | `403` | The key only works from certain IP addresses, and this request came from another one. |
| [`rate_limited`](https://docs.theavoxai.com/api/errors#rate_limited) | `429` | Also returned when one address sends many wrong keys in a short time. Fix the key before retrying. |

## Keeping keys safe

- **Server side only.** Keep the key in an environment variable or a secrets manager. Never put it
  in a website, a mobile app, a public repository, or a shared automation template.
- **One key per system.** Give each server or integration its own key. Then you can revoke one
  without touching the others, and the recent-requests list tells you which system sent what.
- **Watch the warnings.** **Settings > API Keys** highlights a key that needs attention, with a
  warning such as **Used from a new place**, **Blocked request from an unknown address**, **Far
  more requests than usual**, **Requests are failing**, **Hit its per-minute limit** or **Hit its
  daily limit**. You also get a notification in the dashboard.
- **Check the API logs.** The **API logs** page lists every request made with your keys, with the
  calling IP address. Filter by key to see exactly what one system has been doing. See
  [API logs](https://docs.theavoxai.com/connections/api-keys#api-logs).
- **Restrict by IP address.** A key can be limited to your servers' addresses. Contact
  [Support](https://docs.theavoxai.com/support) to set or change the list.
- **Use test keys while you build.** A test key can't send a real message, so a leaked test key
  can't reach your customers. See [Testing](https://docs.theavoxai.com/avox-api/testing#1-test-mode).

## Rotating a key

**Rotate** swaps a key for a new one with no downtime. The new key keeps the old one's name, number,
mode (a test key rotates into a new test key), description and limits, and the old key keeps working
for the grace period you pick.

Rotating never resets anything. The new key gets the limits the old key has at that moment (allowed
IPs, per-minute limit, daily allowance), and the counts carry on: requests made with the old key
today count toward the new key's daily allowance, and both keys share the per-minute limit while both
work. A rotation can't be used to get a fresh allowance.

**1. Click Rotate**

Click **Rotate** on the key in **Settings > API Keys** or on the connection's page.

**2. Pick the grace period**

**Immediately**, **In 1 hour**, **In 24 hours** or **In 7 days**. Both keys work until it ends.

**3. Confirm with the emailed code**

Click **Email me a code to rotate** and type the 6-digit code.

**4. Deploy the new key**

Copy it from **Your rotated API key**, update the secret on every server that sends, and redeploy.

**5. Check the old key is idle**

On the [API logs](https://docs.theavoxai.com/connections/api-keys#api-logs), filter by the old key and confirm nothing new is arriving. Its row shows "Expires in ..." until it stops.

After the grace period the old key fails with [`key_expired`](https://docs.theavoxai.com/api/errors#key_expired). Full details:
[Rotate a key](https://docs.theavoxai.com/connections/api-keys#rotate-a-key).

- A key can be rotated once. **Rotate** is hidden on a key that's already counting down; rotate its
  replacement instead.
- Rotating doesn't move the old key's history: [`Idempotency-Key`](https://docs.theavoxai.com/avox-api/idempotency) values
  belong to one API key, so a retry sent with the new key runs as a new request. Finish any
  retries in flight before you switch, or accept that one message could go out twice.

## Revoking a key

Click the bin button (**Revoke this key**) next to the key in **Settings > API Keys** or on the
connection's page, then **Email me a code to revoke** and type the 6-digit code. A revoked key stops
working on the very next request, with
[`key_revoked`](https://docs.theavoxai.com/api/errors#key_revoked), and moves to **Revoked and expired keys** in **Settings >
API Keys**. Revoking can't
be undone - create a new key if you need one again. Its past requests stay on the API logs.

> **Warning**
>
> If a key may have leaked, rotate it with **Immediately** (or revoke it). It fails with
> [`key_expired`](https://docs.theavoxai.com/api/errors#key_expired) or [`key_revoked`](https://docs.theavoxai.com/api/errors#key_revoked) on the very
> next request.
