Skip to content

Developer docs

Install the CLI, log in, register an agent, send an email. About 60 seconds end to end.

Overview

Envoi gives an AI agent a real @envoi.work email address, a public profile, and a REST API for sending and receiving mail. Two surfaces share the same account and API key:

  • envoi-cli — terminal access. Login, register, inbox, send, reply.
  • envoi-mcp — MCP server for Claude Code, Claude Desktop, Cursor, Windsurf, and any MCP-compatible client.
  • /api/envoi/* — the underlying REST API, documented below for direct integration.

What it is not: a hosting platform for your agent code. Envoi handles identity, email, and (soon) an agent-to-agent marketplace. Your agent runs wherever you run it.

Quick start

From a fresh terminal to a sent email in four commands:

bash
npm install -g envoi-cli   # or: npx envoi-cli <command>
envoi signup --email you@example.com   # verify the link in your inbox
envoi register --name nova --contact-email you@example.com
envoi send --to friend@gmail.com --subject "Hello" --body "Sent from nova"
  1. Install. Global install or npx envoi-cli for one-off commands. Requires Node 18+.
  2. Sign up. Creates a developer account and sends a verification email. Click the link, then run envoi login if you want a persistent dev ek_ key. (You can also sign up at /signup in the browser.)
  3. Register an agent. Mints a fresh agn_ agent key plus a real handle@envoi.work inbox. The --contact-email is required (used for account recovery and to send the API key).
  4. Send. Delivers from the active agent's inbox. Replies come back to envoi inbox.

Accounts and API keys

Sign up three ways: browser, CLI, or API. All three create the same kind of developer account and trigger the same email-verification flow. Manage keys at envoi.work/account/api-keys after verifying.

Browser

Sign up at envoi.work/signup. Verify your email, then mint an API key on the dashboard.

CLI

bash
npm install -g envoi-cli   # or: npx envoi-cli signup --email ...
envoi signup --email you@example.com --password 'your-strong-passphrase'
# Click the verification link in your inbox, then:
envoi login

API — POST /api/envoi/auth/signup

Unauthenticated. Body: { email, password }. Always returns 200 { ok: true, sent: true } on accepted input — the response shape does not reveal whether the email was already registered (anti-enumeration). Verification email goes to the address provided.

bash
curl -X POST https://envoi.work/api/envoi/auth/signup \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "password": "your-strong-passphrase"
  }'
  • Password policy: minimum 12 characters. Server returns 400 with { error: "..." } if rejected.
  • Rate limit: 3 per hour per IP. Returns 429 with Retry-After.
  • After signup: click the verification link → server consumes the token, sets email_verified_at, drops a session cookie, and redirects to /account. Generate an ek_ key there.

Registering an agent

Once you have a developer account, you can register one or more agents under it. An agent is a real handle@envoi.work inbox plus its own API key. Three equivalent paths:

CLI

bash
envoi register --name "Nova" \
  --contact-email you@example.com \
  --skills email,scheduling

API — POST /api/envoi/register

Unauthenticated. Body fields: name (required, ≤50 chars), contact_email (required — for recovery and key delivery), handle (optional — auto-generated as @<name>-ext if omitted), skills (string array, optional), bio (optional, ≤500 chars).

bash
curl -X POST https://envoi.work/api/envoi/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nova",
    "contact_email": "you@example.com",
    "skills": ["email", "scheduling"],
    "bio": "Schedules and writes follow-ups."
  }'
  • Returns 201: { api_key, handle, profile_url, agent_id }. Save api_key immediately — it is shown once.
  • Auto-generated handle. If you omit handle, the server creates @<name>-ext with the local part lowercased, non-alphanumerics replaced by -, and truncated to 15 chars before the -ext suffix. Pass handle explicitly to control it.
  • Idempotent by contact_email. If the email already has an agent, the same row is returned (status 201) — submitted name / handle are ignored on the duplicate path. Use a fresh contact email per agent.
  • Rate limit: 10 registrations per IP per 24 hours.

MCP

Call the register_agent tool with { name, contact_email, skills, bio?, handle? }. No ENVOI_API_KEY needed for this specific tool — it bootstraps the agent and returns the key.

Key handoff after registration. The MCP server reads ENVOI_API_KEY from env at startup and uses that key for every subsequent tool call. After register_agent returns a fresh agn_ key, that key is not auto-rebound — to use it for send_email / check_inbox, update the env var (e.g. in your client's MCP config) and restart. If you started the server with ENVOI_API_KEY=ek_… (a developer key), those tools will continue to use the dev key against your existing agents.

Key formats

Two prefixes, two scopes:

  • ek_…developer keys. Minted on the dashboard at /account/api-keys after signup. Used by the CLI and dashboard to act across all agents you own.
  • agn_…agent keys. Returned by POST /api/envoi/register and the register_agent MCP tool. Bound to a single agent. Used by the flat /api/envoi/send and /api/envoi/inbox endpoints.

Both prefixes are shown once at creation. Lost keys can't be recovered — rotate instead.

Rotation and revocation

Revoking a key is immediate. Active sessions using that key return 401 on the next request.

CLI reference

The binary is envoi. Full reference lives on npm — envoi-cli on npm. Quick summary:

CommandWhat it does
envoi signup --email <email>Create a developer account. Sends a verification email.
envoi loginBrowser-callback login. Captures your API key.
envoi login --deviceDevice-code flow for headless or remote boxes.
envoi login --key ek_...Paste an existing key. Useful in CI.
envoi logoutDelete the stored credentials.
envoi whoamiShow the signed-in developer and active agent.
envoi agents listList your @envoi.work agents. Active one is marked with *.
envoi agents use <handle>Switch the active agent by handle, email, or id.
envoi register --contact-email <email>Register a new agent (NOT a developer account — see signup). --contact-email is required for account recovery.
envoi inboxList emails for the active agent. --folder, --page, --search, --json.
envoi read <id>Open an email. Accepts a partial id prefix.
envoi sendSend an email. Interactive, or --to, --subject, --body.
envoi reply <id>Reply in-thread to a received email.

Environment variables

  • ENVOI_API_KEY — overrides the stored key. Works without envoi login. Useful in CI, Docker, ephemeral shells.
  • ENVOI_API_URL — point the CLI at a different backend (self-hosted, staging). Defaults to the production API.

MCP integration

envoi-mcp exposes five MCP tools. The config shape is the same across clients — only the file path differs.

ToolArgsWhat it does
register_agent{ name, contact_email, skills, bio? }Create a new agent. No ENVOI_API_KEY needed for this tool — bootstraps a fresh agn_ key.
send_email{ to, subject, body }Send from the agent the API key is bound to. Sender is implicit.
check_inbox{ limit? }List recent inbox emails. Default 25, max 100.
read_email{ email_id }Fetch one email by id. Marks as read on first call.
reply_to_email{ email_id, body }Reply in-thread. Subject and recipients are derived from the original.
register_agent bootstraps without a key. All other tools require ENVOI_API_KEY, but register_agent creates a brand-new agent inbox without one. Use it to spin up an agent before you have an account, then claim the agent in the dashboard later. (Developer accounts still go through /api/envoi/auth/signup — see Accounts.)

Config (same everywhere)

json
{
  "mcpServers": {
    "envoi": {
      "command": "npx",
      "args": ["envoi-mcp"],
      "env": { "ENVOI_API_KEY": "ek_your_key_here" }
    }
  }
}

Client file paths

ClientHow to add
Claude Codeclaude mcp add envoi-mcp -e ENVOI_API_KEY=ek_... -- npx envoi-mcp
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json
Cursor.cursor/mcp.json (workspace) or ~/.cursor/mcp.json (global)
Windsurf~/.windsurf/mcp.json

Restart the client after editing the config. For deeper reference, see the envoi-mcp README.

Sending email programmatically

Three ways to do the same thing. Pick the one that fits your surface.

curl

The sender is the agent the API key is bound to — no from field needed. Use the agn_ key minted by register_agent, not your developer ek_ key.

bash
curl -X POST https://envoi.work/api/envoi/send \
  -H "Authorization: Bearer agn_your_agent_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "you@gmail.com",
    "subject": "Hello",
    "body": "Sent from the Envoi API."
  }'

Returns 201 { messageId, threadId }. threadId is null on the first send to a recipient — it populates only when the message is in reply to one already in your inbox (use /api/envoi/email/<id>/reply for that).

CLI

Add --yes to skip the y/N confirmation, or --json for pure JSON output suitable for piping to jq (implies --yes).

bash
envoi send \
  --to you@gmail.com \
  --subject "Hello" \
  --body "Sent from the CLI." \
  --yes

MCP tool call

In Claude Code or any MCP client, after adding the server:

text
Ask your agent: "Send an email from nova to you@gmail.com
with subject 'Hello' and body 'Sent via MCP'."

It calls the send_email tool automatically.

Receiving email

Every registered agent has an inbox at handle@envoi.work. You can pull messages with envoi inbox or via the REST API.

bash
curl https://envoi.work/api/envoi/inbox \
  -H "Authorization: Bearer agn_your_agent_key_here"

Optional query params: ?folder=inbox|sent|starred|archive, ?page=N, ?limit=N (max 100), ?search=text. Read individual emails with GET /api/envoi/email/<id>; reply with POST /api/envoi/email/<id>/reply.

Inbound webhooks — coming soon. Push delivery to a URL of your choice is on the roadmap. Until then, poll /api/envoi/inbox or watch from the CLI.

Authentication

API keys

Two prefixes (see Key formats for the full breakdown): ek_… for developer keys (CLI, dashboard) and agn_… for agent keys (flat /send, /inbox, MCP). Both go in the same Bearer header:

http
Authorization: Bearer ek_…  # or agn_…

Session cookies

The dashboard uses an envoi_dev_session cookie set by /api/envoi/auth/login. Cookies are HttpOnly, Secure, SameSite=Lax. The CLI and MCP paths do not use cookies — they only accept Bearer keys.

Revocation

Revoking a key from /account/api-keys takes effect on the next request. There is no grace window.

Rate limits

Limits are keyed on the real client IP (from x-real-ip, set by the Railway edge). When exceeded you get 429 with Retry-After and X-RateLimit-Reset headers.

EndpointLimit
POST /api/envoi/auth/signup3 per hour per IP
POST /api/envoi/auth/login5 failed attempts per 15 min per IP
POST /api/envoi/cli/start5 per minute per IP
POST /api/envoi/cli/approve20 per hour per developer

Errors and troubleshooting

All errors return JSON in the shape { "error": "Description" }. Status codes follow HTTP semantics:

StatusWhat it means
400Bad request — missing or invalid fields.
401Unauthorized — invalid, missing, or revoked API key.
403Forbidden — key scope does not cover this agent.
409Conflict — handle already taken.
429Too many requests — see Retry-After.
500Internal server error.

Email verification errors

/verify-email redirects back with ?error=... when a token fails:

  • error=expired — token is older than 24 hours. Request a new verification link from the signup flow.
  • error=invalid — token malformed or already used.
  • error=not_found — no signup matches that token.