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

# Authentication

> Bearer keys, per-inbox scoping, and how to give an agent exactly the access it needs.

Every request carries a bearer token:

```bash theme={null}
curl https://agent.waterr.ai/v0/inboxes \
  -H "Authorization: Bearer $AGENT_MAILBOX_KEY"
```

A missing or unrecognised token returns `401 unauthorized`. A valid token that does not cover the inbox you asked for returns `404 not found` — deliberately, so a scoped key cannot probe which addresses exist on the service.

Two kinds of token work here.

## Your Waterr developer key

If you already have a `wai_` key for the Waterr platform API, it works here too. Nothing to provision:

```bash theme={null}
curl https://agent.waterr.ai/v0/inboxes \
  -H "Authorization: Bearer wai_live_..."
```

The key is scoped to your **workspace**. The first time you use it, a mailbox namespace is created for that workspace automatically, and every inbox you create lands inside it. You see your own inboxes and nobody else's — a request for an address outside your workspace returns `404`, exactly as if it did not exist.

Teammates share it. Anyone with a `wai_` key in the same organization reaches the same inboxes, the same way they already share scenarios and personas in Studio.

<Note>
  A `wai_` key cannot reach the key-management endpoints (`/v0/api-keys`), which stay admin-only. Everything else — inboxes, messages, threads, drafts, events, lists — is available to it.
</Note>

## Native mailbox keys

`aik_` keys are issued by this service and are the right choice when you want scoping narrower than a whole workspace — a key that reaches exactly one inbox, for example, so a single agent cannot touch the others.

Agent Mailbox is in limited access while outbound deliverability is being hardened, so these are issued per account rather than self-serve.

<Card title="Request access" icon="key" href="mailto:harshit@waterr.ai?subject=Agent%20Mailbox%20access%20request">
  Tell us what you are building and roughly what volume you expect, and we will provision a key and the inboxes to go with it.
</Card>

## Key scopes

There are three kinds of principal.

### Waterr developer key

A `wai_` key, resolved against your Waterr account on each use and scoped to that account's workspace. It carries no inbox list of its own — the workspace is the boundary, so inboxes you create later are covered without re-issuing anything.

Revoking the key in the Waterr dashboard revokes it here. Allow up to a minute for that to take effect, since resolved identities are cached briefly.

### Admin key

The service-wide key. It reaches every inbox, every pod, and the key-management endpoints themselves. Use it from your backend for provisioning; do not hand it to an agent.

### Scoped key

Created through `POST /v0/api-keys`, and constrained at creation time:

```bash theme={null}
curl -X POST "$BASE/v0/api-keys" \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ava-support-agent",
    "inbox_ids": ["ava@agent.waterr.ai"]
  }'
```

```json Response theme={null}
{
  "key_id": "key_7hk2pq4mv8rd3nxz6wbt9cfa",
  "name": "ava-support-agent",
  "api_key": "aik_3mw9qd7kv2npx6rb8tzc4hfj5says0geu1l...",
  "inbox_ids": ["ava@agent.waterr.ai"],
  "created_at": "2026-09-27T10:12:00.144Z"
}
```

<Warning>
  The `api_key` value is returned **once**, at creation. It is not retrievable afterwards — `GET /v0/api-keys` lists metadata only. Store it before you close the response.
</Warning>

| Field       | Effect                                                                         |
| ----------- | ------------------------------------------------------------------------------ |
| `name`      | Required. Shows up in listings; name it after the agent that will hold it.     |
| `inbox_ids` | Restricts the key to these addresses. Omit for every inbox.                    |
| `pod_id`    | Restricts the key to one pod. See [Pods](/agent-mailbox/inboxes#pods).         |
| `scopes`    | Reserved for finer-grained permissions. `permissions` is accepted as an alias. |

An empty `inbox_ids` means *every* inbox, not *no* inboxes. Be deliberate: a key created without it can read every conversation in the service.

### Scope is enforced everywhere

A scoped key cannot widen itself. This matters most on the two surfaces where it would be easy to miss:

* **Webhooks** created with a scoped key are automatically narrowed to that key's inboxes, even if the request asks for more.
* **WebSocket** subscriptions are filtered against the key's scope at subscribe time. Asking for an out-of-scope inbox returns an error frame rather than silently widening the stream.

## WebSocket authentication

Browsers cannot set headers on a WebSocket, so the socket endpoints also accept the key as a query parameter:

```
wss://agent.waterr.ai/v0/ws?api_key=YOUR_KEY
```

This is permitted on `/ws` routes and nowhere else, because query strings are recorded in access logs and proxy traces. Prefer the `Authorization` header wherever your client can send one, and treat any key that has travelled in a URL as lower-trust.

## Rate limiting

Requests are limited **per key** at 300 requests per 60 seconds. Exceeding it returns `429 rate_limited` with a `Retry-After: 60` header.

Because the limit is per key rather than per account, giving each agent its own scoped key also stops one busy agent from throttling the others.

## Revoking

```bash theme={null}
curl -X DELETE "$BASE/v0/api-keys/key_7hk2pq4mv8rd3nxz6wbt9cfa" \
  -H "Authorization: Bearer $ADMIN_KEY"
```

Revocation takes effect on the next request. Rotate by creating the replacement first, moving the agent over, then deleting the old key.
