> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://docs.agentmail.to/llms.txt. For full content including API reference and SDK examples, see https://docs.agentmail.to/llms-full.txt.

## Summary

Signing in to a provider as an inbox now produces an API key: an inbox-scoped public key, managed with the same list, get, update, and delete calls as every other API key. Start one with provider connect, or authorize a sign-in that is already waiting, then poll it until it is active, list it alongside your bearer keys, and revoke it when it is no longer needed, without handling key material or enrollment internals.

### What's new?

**New endpoints:**

* `POST /v0/inboxes/{inbox_id}/authorize` - Authorize the AgentID sign-in a client is already waiting in, for relying parties reached directly rather than through connect. Mints and returns the inbox's pending public key in the api-keys shape; `accept_disclosure: true` accepts that relying party's disclosure.
* `GET /v0/api-keys/{api_key_id}` - Get one credential of any family. For a sign-in key, poll it to watch `status` go from `pending` to `active`.
* `PATCH /v0/api-keys/{api_key_id}` - Rename or re-permission a bearer key or a public-key credential.

**New features:**

* **One vocabulary for every credential family**: `GET /v0/api-keys` lists every credential in one list, newest first; `type` restricts to one family; the pod- and inbox-nested routes restrict to one scope. Items identify their credential `type` and include applicable scope, permissions, and timestamps. Public keys include `created_by`; sign-in keys add `status`.
* **One handle for the whole lifecycle**: connect responses carry `api_key_id`, the same ID Get, List, and Delete use before and after activation.
* **Delete covers every family**: `DELETE /v0/api-keys/{api_key_id}` deletes a bearer key, revokes a registered public key, cancels a pending sign-in key, or revokes an active one.
* **Sign-in keys carry their own permissions**: exactly `provider_connect` and `provider_share_owner`, snapshotted from the creating bearer key, enforced from the key itself, and editable with `PATCH /v0/api-keys/{api_key_id}`. `provider_share_owner` is one grouped permission: a bearer key holding only one of the older `owner_profile` / `owner_email` permissions mints keys with it `false`.
* **Public keys outlive their creator**: a sign-in key or registered public key is independent of the bearer key that created it. Deleting or narrowing that bearer key afterward does not revoke or change it; `created_by` is provenance only. A sign-in key expires 30 days after activation; a registered key keeps the expiry given at registration.
* **Sign-in is its own permission**: `provider_connect` on a bearer key gates connect, authorize, and minting sign-in keys; `provider_share_owner` gates sharing the owner's name and email with providers. Omitted on a new key means false.
* **Public keys live under api-keys**: `POST /v0/api-keys` with a `public_key` body registers a public-key credential at the route's scope (`/pods/{pod_id}/api-keys` and `/inboxes/{inbox_id}/api-keys` for a pod or inbox, no `scope` body field), and list, get, update, and delete cover it alongside bearer keys.
* **Client IDs for public keys**: register a public key with a caller-chosen `client_id`, unique within the organization across every public key, and use it in place of `api_key_id` on get, update, and delete. Registration is idempotent on it.

### Breaking changes

⚠️ Public-key management now uses the shared API Keys routes. Dedicated credential, enrollment, consent, and bulk-revocation routes have been removed. Remembered consent is managed by AgentID.

Before, creating a pending sign-in key used the inbox API Keys route:

```http
POST /v0/inboxes/{inbox_id}/api-keys
```

Now, authorize a pending sign-in with its `auth_token`:

```http
POST /v0/inboxes/{inbox_id}/authorize
Content-Type: application/json

{"auth_token": "AAAAAAAAAAAAAAAAAAAAAA"}
```

Connect returns `api_key_id`, `magic_url`, and `expires_at`. Use that key ID with the shared API Keys routes for status and revocation.

### Use cases

Build agents that:

* Sign in to a relying party as an inbox and complete the AgentID step with one API call
* Wait on a pending sign-in by polling one endpoint instead of diffing a list
* Audit and revoke every credential that can act as an inbox, bearer and sign-in keys alike, from one list

Python SDK 0.5.10 does not include these routes; the Python example uses `httpx`. The TypeScript example uses SDK 0.5.25.

**`Python`**

```python title="Python"
import os
import uuid
import httpx

response = httpx.post(
    "https://api.agentmail.to/v0/providers/d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32/connect",
    headers={"Authorization": f"Bearer {os.environ['AGENTMAIL_API_KEY']}",
             "Idempotency-Key": str(uuid.uuid4())},
    json={"inbox_id": "agent@example.com"},
    timeout=30,
)
response.raise_for_status()
connection = response.json()
print(connection["magic_url"], connection["api_key_id"])
```

**`TypeScript`**

```typescript title="TypeScript"
import { randomUUID } from "node:crypto";
import { AgentMailClient } from "agentmail";

const client = new AgentMailClient({ apiKey: process.env.AGENTMAIL_API_KEY! });
const connection = await client.providers.connect(
  "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
  { inboxId: "agent@example.com" },
  { headers: { "Idempotency-Key": randomUUID() } },
);
console.log(connection.magicUrl); // open to complete sign-in
const key = await client.apiKeys.get(connection.apiKeyId);
if (key.type === "public_key") console.log(key.status);
```

See the [AgentID Sign-In guide](https://docs.agentmail.to/agentid-sign-in) for setup and the complete flow.