Authentication and keys
Extrovert supports three normal authentication paths:
| Path | Use it when | Result |
|---|---|---|
| Hosted MCP OAuth | A person already has a console account and the MCP client supports remote OAuth | A refreshable grant for the person’s default project and a limited permission set |
| Enrollment key | Setup needs to create the agent | A new or existing agent identity plus a project-bound agent key |
| API key | The agent already exists | A project-bound key for that agent |
Do not give an agent a human session or an organization-wide administrative credential.
Enrollment keys and API keys are different
Section titled “Enrollment keys and API keys are different”The console separates the two under Credentials:
- Enrollment keys bootstrap agents. They may be reusable or single-use, expire independently, and can limit permissions, allowed domains, lifetime inbox creation, and daily sending.
- API keys connect software to an existing active agent. They do not create an agent.
Both raw secrets are shown once. Store them in a secret manager or the packaged MCP credential store.
Redeem an enrollment key
Section titled “Redeem an enrollment key”Redemption is idempotent on agent_handle. Reusing the same stable handle returns the same agent
instead of creating duplicates.
export EXTROVERT_API_BASE_URL="https://api.extrovert.dev"export EXTROVERT_ENROLLMENT_KEY="pk_enroll_…"
curl -sS -X POST "$EXTROVERT_API_BASE_URL/v1/enroll" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: enroll-support-agent" \ -d "{\"token\":\"$EXTROVERT_ENROLLMENT_KEY\",\"agent_handle\":\"support-agent\"}"import { Extrovert } from "@extrovert.dev/sdk";
const bootstrap = new Extrovert({ apiKey: process.env.EXTROVERT_ENROLLMENT_KEY! });const { client, enrollment } = await bootstrap.enrolled({ token: process.env.EXTROVERT_ENROLLMENT_KEY!, agent_handle: "support-agent", client_id: "enroll-support-agent",});
console.log(enrollment.agent_key); // shown once{ "name": "redeem_enrollment", "arguments": { "enrollment_token": "pk_enroll_…", "agent_handle": "support-agent" }}Use the returned agent key as a bearer token:
Authorization: Bearer pk_agent_…Key reach is fixed
Section titled “Key reach is fixed”An agent key has a ceiling that cannot be widened after issuance.
| Ceiling | Prefix | Reach |
|---|---|---|
| Organization | pk_agent_org_… | The bound organization and allowed descendants; console or admin issuance only |
| Project | pk_agent_… | One project; this is the normal enrollment and self-signup result |
| Inbox | pk_agent_inbox_… | One inbox in one project; console or admin issuance only |
pk_agent_proj_… remains accepted as a compatibility form for project keys. A project id in a
request is an assertion, not a selector. If it does not match the key’s project, the request fails.
Call GET /v1/auth/me, client.whoami(), or whoami after connecting. Record the fixed org_id,
project_id, agent id, key id, and permissions before doing work.
Permissions
Section titled “Permissions”The product calls the resource an inbox. Existing mailbox:* strings remain unchanged because
they are part of the public wire contract.
| Permission | Allows |
|---|---|
mailbox:create | Create inboxes and perform owning-agent lifecycle cleanup |
mailbox:read | Read inboxes, messages, threads, rules, review events, suppressions, and contact lists |
mailbox:send | Submit send, reply, forward, review chat, and revision requests |
mailbox:delete | Permanently delete inboxes |
mailbox:credentials | Export portable IMAP and SMTP credentials on an eligible paid plan |
mailbox:quota | Change an inbox’s rolling 24-hour recipient limit |
webhook:write | Create, update, and delete webhooks; older keys may use the documented read fallback |
domain:manage | Onboard, verify, inspect, and offboard customer-controlled domains |
commerce:request | Quote and request a domain purchase or plan change; never approve or authorize spending |
review:act | Act as a linked Review Loop reviewer; the link is also required |
signup:verify | Verify a self-signup code only |
domain:purchase is a legacy compatibility permission. New agent credentials should use
commerce:request for human-controlled purchase requests.
Hosted MCP OAuth
Section titled “Hosted MCP OAuth”Connect an OAuth-capable client to:
https://mcp.extrovert.dev/mcpThe client discovers the authorization server, opens browser sign-in and consent, then stores and refreshes the grant. No Extrovert key belongs in the client configuration.
The grant is pinned to the signed-in person’s default project. Owners, admins, and members receive
inbox create, read, send, webhook, and commerce request permissions. Viewers and billing members
receive read and commerce request permissions. Hosted MCP can also accept a limited pk_agent_…
bearer credential. It rejects enrollment keys.
Free self-signup
Section titled “Free self-signup”When enabled, the flow is:
-
POST /v1/agent/sign-upcreates the agent and an@free.extrovertmail.cominbox, emails a verification code, and returns a temporary project key with onlysignup:verify. -
The temporary key can only verify the OTP. It cannot create, read, send, or export credentials. It expires with the code.
-
POST /v1/agent/verifyatomically revokes the temporary key and returns a new durable key, the activated inbox address, andmailbox_quickstartcalls forread_messages,get_message, andwait_for_email. -
The person signs in to the console with the same verified email. Extrovert presents the matching agent-created account and asks the person to claim it. Accepting the claim grants owner access.
The verification code appears only in email. It is never included in the signup response. If delivery
fails with otp_send_failed, repeat signup with the same normalized email to rotate the temporary key
and send a new code.
Storage and revocation
Section titled “Storage and revocation”The packaged local MCP server stores the durable agent key in a permission-restricted credential file:
- Linux and macOS:
~/.config/extrovert/credentials.jsonor$XDG_CONFIG_HOME/extrovert/credentials.json - Windows:
%APPDATA%\Extrovert\credentials.json
EXTROVERT_API_KEY is an explicit override. Keep secrets out of source files, shell history, logs,
screenshots, and support bundles. Revoke a key that may have been exposed.
Revoking an enrollment key prevents future redemption. It does not revoke agent keys already issued from it. Revoke those keys or disable the agent separately when needed.
Common failures
Section titled “Common failures”| Status or code | Meaning | Next action |
|---|---|---|
401 | The credential is missing, expired, revoked, or invalid | Replace or reconfigure the exact credential |
403 forbidden_scope | The key is valid but lacks a required permission | Issue a narrower-purpose key with the required permission |
403 signup_disabled | Free self-signup or pending verification is paused | Use an enrollment key or wait for the gate to reopen |
404 | The resource is outside the key’s ownership or project reach, or does not exist | Verify whoami, project binding, and the opaque resource id |
409 quota_exceeded or 403 quota_exceeded | A lifetime or plan limit prevents creation | Inspect the returned problem details and issue a new key or change plan capacity as appropriate |