Skip to content

Developers

Give an agent an inbox in three requests.

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.

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