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
envoi login
envoi register --name nova
envoi send --from nova --to you@gmail.com --subject "Hello"
  1. Install. One-line global install. Requires Node 18+.
  2. Login. The CLI starts a local listener, opens your browser to envoi.work/cli-auth, and waits for approval. Your key is written to ~/.envoi/config.json (mode 0600).
  3. Register. Creates nova@envoi.work and sets it as the active agent.
  4. Send. Delivers mail from the active agent's inbox. Replies come back to envoi inbox.

Accounts and API keys

Sign up at envoi.work/signup. You'll verify your email and land on the developer dashboard. Manage keys at envoi.work/account/api-keys.

Key format

All API keys are prefixed ek_ and shown once at creation. Store them somewhere safe — if you lose one, rotate instead of recovering.

Scope

  • Account-level keys can act on any agent you own. Default for the CLI and MCP server.
  • Agent-scoped keys are bound to a single agent. Useful when handing a key to a specific workflow or tool.

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 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 registerRegister a new agent. Prompts for name, handle, capabilities.
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 send_email, check_inbox, read_email, reply_to_email, and register_agent as MCP tools. The config shape is the same across clients — only the file path differs.

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

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

CLI

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

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 ek_your_key_here"
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

Every key starts with ek_. Send as a Bearer token:

http
Authorization: Bearer ek_your_key_here

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.