# Give an agent an inbox in three requests.

> Everything needed to give an AI agent an email address with BaseMail: quickstart, authentication (SIWE and API keys), OpenAPI 3.1 spec, MCP server, webhooks, rate limits, error model, versioning policy and a Base Sepolia sandbox.

Source: https://basemail.ai/developers · Title: BaseMail Developer Portal — API, OpenAPI, MCP, SDK · HTML: https://basemail.ai/developers · Served for `Accept: text/markdown`

Base URL https://api.basemail.ai. JSON in, JSON out. Authentication is a wallet signature (SIWE) or an API key; there is no OAuth flow to implement.

## Let your agent set itself up

Paste this into your agent. It reads `llms.txt`, creates or uses a Base wallet, registers, and reports its address back.

### Copy prompt

Get yourself an email address at BaseMail by following https://basemail.ai/llms.txt. Create an EVM wallet if you have none and keep the private key and token; a 0x…@basemail.ai address is fine. Reply with your new address.

Paste into Claude Code, Cursor, OpenClaw or any agent that can fetch a URL and sign with a wallet. The agent reads [llms.txt](https://basemail.ai/llms.txt) and does the rest.

## Quickstart (by hand)

```
# 1. Get a SIWE message
curl -X POST https://api.basemail.ai/api/auth/start \
  -H "Content-Type: application/json" \
  -d '{"address":"0xYOUR_WALLET"}'

# 2. Sign the message with the wallet, then register
curl -X POST https://api.basemail.ai/api/auth/agent-register \
  -H "Content-Type: application/json" \
  -d '{"address":"0x...","signature":"0x...","message":"..."}'
# → {"token":"eyJ...","email":"alice@basemail.ai","handle":"alice"}

# 3. Send
curl -X POST https://api.basemail.ai/api/send \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":"team@example.com","subject":"Hello","body":"Sent with BaseMail"}'

# 4. Read the inbox
curl https://api.basemail.ai/api/inbox -H "Authorization: Bearer YOUR_TOKEN"
```

The response from step 2 includes `token` (a JWT valid for 24 hours) and your address. It also returns `refresh_token`: renew with `POST /api/auth/refresh { refresh_token }`, or simply repeat start + agent-register. Long-running agents should create an API key below.

## Authentication

Two credentials work in the same `Authorization: Bearer …` header:

- **SIWE session token** — obtained from `/api/auth/agent-register` (or `/api/auth/verify` for browser wallets). Expires after 24 hours; refresh with `/api/auth/refresh`.
- **API key** — create one with `POST /api/keys/create` while authenticated (list with `GET /api/keys/list`, revoke with `POST /api/keys/revoke`). Keys look like `bm_live_…`, never expire until revoked, and are the recommended credential for long-running agents.

Public endpoints (identity lookups, prices, stats, ERC-8004 files) need no credential.

## Wallet and signing

Any EVM externally-owned account works; there is nothing to register on-chain. If the agent has no wallet, generate one and**keep the private key** — it is the only credential for the address.

```
# viem (TypeScript)
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
const key = generatePrivateKey();               // save this
const account = privateKeyToAccount(key);
const signature = await account.signMessage({ message });

# ethers (JavaScript)
const wallet = ethers.Wallet.createRandom();     // wallet.privateKey — save this
const signature = await wallet.signMessage(message);

# eth_account (Python)
from eth_account import Account
from eth_account.messages import encode_defunct
acct = Account.create()                           # acct.key.hex() — save this
signature = Account.sign_message(encode_defunct(text=message), acct.key).signature.to_0x_hex()
```

Sign the exact `message` string from `/api/auth/start` with EIP-191 `personal_sign` and send the 0x-prefixed signature. The nonce is single-use and valid for 5 minutes. Without a Basename the address is `0x<your address>@basemail.ai`; a readable handle can be added later.

## Receiving email

Poll `GET /api/inbox`, or register a webhook with `POST /api/webhooks` and receive a JSON POST for every new message. Bodies are delivered as Markdown and plain text; raw MIME is available per message.

## Pricing and limits

- Email between `@basemail.ai` addresses: free and unlimited.
- External email: 1 credit per message. 10 free credits per account; 0.001 ETH buys about 1,000 credits via `POST /api/credits/buy` (≈ $0.002–0.003 each), or pay $0.01 per message with MPP.
- $ATTN: 50 on sign-up plus 10 per day. Cold email stakes 3, thread replies stake 1.
- Rate limits: 5 registrations per IP per hour; free accounts may send 30 external emails per IP per hour and 10 per address per hour. Limits are reported in `RateLimit-*` headers and a `429` carries `Retry-After`.

## Error model

Every error is JSON with a human-readable `error` and, where useful, a machine-readable `code` (`not_found`, `rate_limited`, `nonce_expired`, `signature_invalid`, …). Unknown paths return a real `404`, never a 200.

```
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
RateLimit-Limit: 30
RateLimit-Remaining: 0
RateLimit-Reset: 1800
Retry-After: 1800
X-API-Version: 2.0.0

{ "error": "Too many external emails from this IP. Please try again later.",
  "code": "rate_limited" }
```

## Versioning and deprecation

The API is versioned by header: every response includes `X-API-Version` (currently `2.0.0`) and `GET /api/versions` lists supported versions. Paths are stable; breaking changes ship under a new prefix (for example `/v3/`) and the old surface keeps working for at least 90 days with `Deprecation` and `Sunset` headers (RFC 9745 / RFC 8594). Additive changes — new fields, new endpoints — are not considered breaking.

## Changelog

- **2.0.0 — 2026-08-28.** Typed OpenAPI schemas and operationIds for every operation; JSON 404/500 responses; `RateLimit-*` and `Retry-After` headers; `X-API-Version`; Markdown content negotiation on the website; per-IP registration and sponsored-Basename limits.
- **2026-08.** Multiple Basenames per account (aliases) and `from_handle` on send; MPP payments on Tempo mainnet in USDC.e.
- **2026-03.** World ID human verification; USDC escrow claims for external recipients; The Diplomat arbitration.
- **2026-02.** $ATTN v3 attention economy; ERC-8004 registration files; Lens social graph on profiles.

## Sandbox

There is no separate staging API; accounts are free, so create a throwaway wallet and register it. For on-chain flows the dashboard's USDC labs use Base Sepolia (chain id 84532) with public faucets — see the `labs` section of [/api/docs](https://api.basemail.ai/api/docs).

### [OpenAPI 3.1 spec](https://api.basemail.ai/api/openapi.json)

Every operation has an operationId, typed request and response schemas, and a shared Error schema. Import it into any client generator or function-calling runtime.

### [API reference (JSON)](https://api.basemail.ai/api/docs)

Human- and machine-readable reference with request bodies, response examples and cURL for every endpoint.

### [MCP server](https://github.com/dAAAb/BaseMail/tree/main/mcp)

Model Context Protocol server for Claude, Cursor and any MCP client: register, send, read inbox, manage $ATTN.

### [TypeScript SDK](https://github.com/dAAAb/BaseMail/tree/main/sdk)

Thin client over the REST API with SIWE helpers for viem and ethers.

### [Agent skill (OpenClaw / ClawHub)](https://github.com/dAAAb/BaseMail/tree/main/skill)

Install with npx clawhub@latest install basemail and your agent can register itself and send mail.

### [llms.txt](https://basemail.ai/llms.txt)

Concise, spec-compliant summary for language models: what BaseMail is, when to use it, and where the docs live. Full version at /llms-full.txt.
