# Mail.td API — LLM Reference > Developer email platform. Create email addresses and receive emails via REST API. ## Base URL https://api.mail.td ## Authentication All authenticated requests require: `Authorization: Bearer ` Three token types (all use the same header): - Email JWT: from `POST /api/accounts` or `POST /api/token`, expires in 7 days, accesses 1 account - Pro JWT: from `POST /api/user/login`, expires in 7 days, accesses all accounts owned by the user - Pro API Token: prefix `tm_pro_`, never expires, accesses all accounts owned by the user ## API Pattern All email operations follow: ``` /api/accounts/{account_id}/messages ``` Free and Pro users use the SAME endpoints. The only difference is what accounts a token can access. ## Public Endpoints (no auth required) ### List Available Domains GET /api/domains → 200: { "domains": [{ "id": "uuid", "domain": "mail.td", "default": true }] } ### Get PoW Challenge (free users) GET /api/challenge → 200: { "id": "string", "salt": "hex", "difficulty": 20, "expires_at": unix_ts } Client must find nonce where SHA-256(salt + nonce) has `difficulty` leading zero bits. ### Create Account POST /api/accounts Body: { "address": "user@mail.td", "password": "string", "pow": { "id": "challenge_id", "nonce": "solution" } } → 201: { "id": "account_id", "address": "user@mail.td", "token": "jwt" } IMPORTANT: Save both `id` and `token`. The `id` is used as {account_id} in all paths below. Note: Free users must include `pow` (from GET /api/challenge). Pro users with a Bearer token skip PoW. ### Email Login POST /api/token Body: { "address": "user@mail.td", "password": "string" } → 200: { "id": "account_id", "address": "user@mail.td", "token": "jwt" } ## Account Endpoints (auth required) ### Get Account Info GET /api/accounts/{account_id} → 200: { "id", "address", "role", "quota", "used", "created_at" } ### Delete Account DELETE /api/accounts/{account_id} → 204 ### Reset Password PUT /api/accounts/{account_id}/reset-password Body: { "password": "newpassword" } → 200: { "message": "password_reset" } ## Message Endpoints (auth required) ### List Messages GET /api/accounts/{account_id}/messages?page=1 → 200: { "messages": [{ "id", "sender", "from", "subject", "preview_text", "size", "is_read", "created_at" }], "page": 1 } Pagination: 30 per page. Fewer than 30 = last page. ### Get Message Detail GET /api/accounts/{account_id}/messages/{id} → 200: { "id", "sender", "from", "subject", "address", "size", "created_at", "text_body", "html_body", "attachments": [{ "index", "filename", "content_type", "size" }] } ### Delete Message DELETE /api/accounts/{account_id}/messages/{id} → 204 ### Download Raw Source (.eml) GET /api/accounts/{account_id}/messages/{id}/source → 200: Content-Type: message/rfc822 ### Download Attachment GET /api/accounts/{account_id}/messages/{id}/attachments/{index} → 200: binary content ### Mark as Read PUT /api/accounts/{account_id}/messages/{id}/read → 204 ### Batch Mark as Read PUT /api/accounts/{account_id}/messages/read Body: { "ids": ["id1", "id2"] } or { "all": true } → 200: { "updated": 5 } ## WebSocket (real-time notifications) Connect: wss://api.mail.td/api/ws Auth: send `{ "type": "auth", "token": "jwt" }` within 10 seconds Success: `{ "type": "auth_ok" }` New email event: `{ "type": "new_email", "id", "sender", "from", "subject", "preview_text", "size", "created_at", "account_id", "address" }` Note: Only Email JWTs work for WebSocket. Pro tokens do not. ## Pro User Endpoints (Pro auth required) ### Pro Login POST /api/user/login Body: { "email": "user@example.com", "password": "string" } → 200: { "user_id", "email", "plan", "status", "downgraded" } Note: Session token set via cookie. OAuth users (Google/GitHub) should use Pro API Tokens instead. ### Pro Register POST /api/user/register Body: { "email": "user@example.com", "password": "string" } → 201: { "user_id", "email", "plan": "pro", "status": "pending" } Note: Session token set via cookie. ### Get Pro Profile GET /api/user/me → 200: { "id", "email", "plan", "role", "status", "max_accounts", "max_domains", "account_count", "domain_count", "created_at" } ### List All Accounts GET /api/user/accounts → 200: { "accounts": [{ "id", "address", "quota", "used", "created_at" }] } ### Create API Token POST /api/user/tokens Body: { "name": "my-token" } → 201: { "id", "name", "token": "tm_pro_..." } IMPORTANT: Token value is shown only once. ### List API Tokens GET /api/user/tokens → 200: { "tokens": [{ "id", "name", "last_used_at", "created_at" }] } ### Revoke API Token DELETE /api/user/tokens/{id} → 204 ### Add Custom Domain POST /api/user/domains Body: { "domain": "example.com" } → 201: { "id", "domain", "verify_token", "dns_records": [...] } ### List Custom Domains GET /api/user/domains → 200: { "domains": [{ "id", "domain", "verify_status", "mx_configured", "created_at" }] } ### Verify Domain POST /api/user/domains/{id}/verify → 200: { "verify_status": "verified"|"pending", "txt_record": bool, "mx_record": bool } ### Delete Domain DELETE /api/user/domains/{id} → 204 ### Create Webhook POST /api/user/webhooks Body: { "url": "https://example.com/hook", "events": ["email.received"] } → 201: { "id", "url", "events", "secret": "whsec_...", "created_at" } ### List Webhooks GET /api/user/webhooks → 200: { "webhooks": [{ "id", "url", "events", "status", "failure_count", "created_at" }] } ### Delete Webhook DELETE /api/user/webhooks/{id} → 204 ### Rotate Webhook Secret POST /api/user/webhooks/{id}/rotate → 200: { "id", "secret": "whsec_..." } ### List Webhook Deliveries GET /api/user/webhooks/{id}/deliveries → 200: { "deliveries": [{ "id", "event_type", "status_code", "error", "attempt", "duration_ms", "created_at" }] } ## Rate Limits - Public endpoints: 8 req/s per IP - Free authenticated: 8 req/s per IP - Pro authenticated: 20 req/s per IP - Account creation (free): 1 per 8 seconds per IP - Account creation (Pro): 8 req/s per IP (no slow limit) ## Error Format All errors return: { "error": "error_code" } Common codes: - 400: invalid_address, invalid_domain, password_too_short - 401: invalid_credentials, invalid_or_expired_token, account_revoked - 403: access_denied, pro_required, account_limit_reached - 404: account_not_found, email_not_found - 409: address_taken - 410: email_expired - 429: rate_limit_exceeded ## Quick Start Example (Python) ```python import requests API = "https://api.mail.td/api" # 1. Create account r = requests.post(f"{API}/accounts", json={"address": "test@mail.td", "password": "secret123"}) account_id = r.json()["id"] token = r.json()["token"] # 2. Read messages headers = {"Authorization": f"Bearer {token}"} msgs = requests.get(f"{API}/accounts/{account_id}/messages", headers=headers).json() for m in msgs["messages"]: detail = requests.get(f"{API}/accounts/{account_id}/messages/{m['id']}", headers=headers).json() print(detail["subject"], detail["text_body"]) ```