Skip to content

Authentication and keys

Extrovert supports three normal authentication paths:

PathUse it whenResult
Hosted MCP OAuthA person already has a console account and the MCP client supports remote OAuthA refreshable grant for the person’s default project and a limited permission set
Enrollment keySetup needs to create the agentA new or existing agent identity plus a project-bound agent key
API keyThe agent already existsA 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.

Redemption is idempotent on agent_handle. Reusing the same stable handle returns the same agent instead of creating duplicates.

Terminal window
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\"}"

Use the returned agent key as a bearer token:

Authorization: Bearer pk_agent_…

An agent key has a ceiling that cannot be widened after issuance.

CeilingPrefixReach
Organizationpk_agent_org_…The bound organization and allowed descendants; console or admin issuance only
Projectpk_agent_…One project; this is the normal enrollment and self-signup result
Inboxpk_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.

The product calls the resource an inbox. Existing mailbox:* strings remain unchanged because they are part of the public wire contract.

PermissionAllows
mailbox:createCreate inboxes and perform owning-agent lifecycle cleanup
mailbox:readRead inboxes, messages, threads, rules, review events, suppressions, and contact lists
mailbox:sendSubmit send, reply, forward, review chat, and revision requests
mailbox:deletePermanently delete inboxes
mailbox:credentialsExport portable IMAP and SMTP credentials on an eligible paid plan
mailbox:quotaChange an inbox’s rolling 24-hour recipient limit
webhook:writeCreate, update, and delete webhooks; older keys may use the documented read fallback
domain:manageOnboard, verify, inspect, and offboard customer-controlled domains
commerce:requestQuote and request a domain purchase or plan change; never approve or authorize spending
review:actAct as a linked Review Loop reviewer; the link is also required
signup:verifyVerify a self-signup code only

domain:purchase is a legacy compatibility permission. New agent credentials should use commerce:request for human-controlled purchase requests.

Connect an OAuth-capable client to:

https://mcp.extrovert.dev/mcp

The 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.

When enabled, the flow is:

  1. POST /v1/agent/sign-up creates the agent and an @free.extrovertmail.com inbox, emails a verification code, and returns a temporary project key with only signup:verify.

  2. The temporary key can only verify the OTP. It cannot create, read, send, or export credentials. It expires with the code.

  3. POST /v1/agent/verify atomically revokes the temporary key and returns a new durable key, the activated inbox address, and mailbox_quickstart calls for read_messages, get_message, and wait_for_email.

  4. 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.

The packaged local MCP server stores the durable agent key in a permission-restricted credential file:

  • Linux and macOS: ~/.config/extrovert/credentials.json or $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.

Status or codeMeaningNext action
401The credential is missing, expired, revoked, or invalidReplace or reconfigure the exact credential
403 forbidden_scopeThe key is valid but lacks a required permissionIssue a narrower-purpose key with the required permission
403 signup_disabledFree self-signup or pending verification is pausedUse an enrollment key or wait for the gate to reopen
404The resource is outside the key’s ownership or project reach, or does not existVerify whoami, project binding, and the opaque resource id
409 quota_exceeded or 403 quota_exceededA lifetime or plan limit prevents creationInspect the returned problem details and issue a new key or change plan capacity as appropriate