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. Every item carries type, pod_id, inbox_id, permissions, created_by, and the timestamps, scope expressed exactly as on a bearer key; a sign-in key adds 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.

Removed:

  • The /v0/api-keys/public-keys list, register, rename, and revoke routes, POST /v0/api-keys/public-keys/agentid-sign-in/revoke-all, and the revoked_at response field. Use the api-keys endpoints above; revoke keys individually.
  • GET /v0/api-keys/browser-credentials and its events, enrollments, and {credential_id} routes, POST /v0/inboxes/{inbox_id}/browser-credentials/enrollments, and both /v0/api-keys/browser-consents routes. Remembered consent is managed by AgentID and is no longer listed or revoked through the API.
  • POST /v0/api-keys and POST /v0/inboxes/{inbox_id}/api-keys no longer mint sign-in keys; use POST /v0/inboxes/{inbox_id}/authorize.
  • The session_id field on connect responses, and the enrollment_endpoint, browser_credentials_endpoint, and browser_consents_endpoint fields of GET /v0/.well-known/agentid-configuration.

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
from agentmail import AgentMail
client = AgentMail(api_key="your-api-key")
# start signing the inbox in to a provider
connect = client.providers.connect(
provider_id="00000000-0000-4000-8000-000000000000",
inbox_id="agent@example.com",
)
print(connect.magic_url) # open in the client that will hold the key
# poll until the sign-in is active
key = client.api_keys.get(api_key_id=connect.api_key_id)
print(key.status)

See the API Keys reference and the AgentID Sign-In guide for the full flow.