# x402email — Pay-per-send email via x402 protocol > Send email with a single HTTP request. No API keys. No accounts. Pay $0.02 per email. ## Base URL https://x402email.com ## x402 Discovery GET /.well-known/x402 ## Endpoints ### POST /api/send — Send email (shared domain) - Protection: x402 payment ($0.02 USDC on Base) - Sends from: relay@x402email.com - Body: { "to": ["email"], "subject": "string", "html": "string", "text": "string", "replyTo": "email", "attachments": [{"content": "base64...", "contentType": "application/pdf", "filename": "file.pdf"}] } - Requires either "html" or "text" (or both) - "attachments" is optional, max 5, each with base64 content (~3.75MB decoded limit), MIME contentType, and filename - For calendar invites (.ics), use contentType: "text/calendar; method=REQUEST" - Returns: { "success": true, "messageId": "string", "from": "string" } ### POST /api/subdomain/buy — Purchase a custom subdomain - Protection: x402 payment ($5 USDC) - Body: { "subdomain": "yourname" } - Subdomain rules: 3-30 chars, lowercase alphanumeric + hyphens - Creates yourname.x402email.com with full email sending capability - DNS verification takes ~5 minutes after purchase - Returns: { "success": true, "subdomain": "yourname.x402email.com", "dnsStatus": "pending" } ### POST /api/subdomain/send — Send from custom subdomain - Protection: x402 payment ($0.005 USDC) - Payer wallet must be owner or authorized signer for the subdomain - Body: { "from": "you@yourname.x402email.com", "to": ["email"], "subject": "string", "html": "string", "text": "string", "replyTo": "email" } - Returns: { "success": true, "messageId": "string", "from": "string" } ### POST /api/subdomain/signers — Manage authorized wallets - Protection: SIWX wallet proof only (free, no payment) - Only the subdomain owner can manage signers - Body: { "action": "add" | "remove", "subdomain": "yourname", "walletAddress": "0x..." } - Max 50 signers per subdomain ### POST /api/subdomain/update — Update subdomain settings - Protection: SIWX wallet proof only (free, no payment) - Only the subdomain owner can update - Body: { "subdomain": "yourname", "catchAllForwardTo": "catch-all@example.com" } - Set catchAllForwardTo to null to remove catch-all forwarding - Catch-all forwards emails to unmatched addresses on the subdomain ### GET /api/subdomain/status?subdomain=yourname — Check subdomain status - Protection: SIWX wallet proof only (free, no payment) - Owner or any signer can check status - Returns: { "subdomain": "string", "ownerWallet": "string", "dnsVerified": bool, "sesVerified": bool, "signerCount": number, "signers": ["0x..."] } ## Subdomain Inboxes — Receive Email on Subdomains Subdomain owners can create per-address inboxes on their subdomain (e.g., `biden@craig.x402email.com`). $0.25 to create (x402 payment), cap 100 per subdomain. Each inbox optionally forwards to a real address and/or retains messages for programmatic API access. Unmatched addresses go to the subdomain's catch-all forwarder if set, otherwise silently dropped. ### POST /api/subdomain/inbox/create — Create inbox on subdomain ($0.25) - Protection: x402 payment ($0.25 USDC on Base) - Payer wallet must be the subdomain owner - Body: { "subdomain": "craig", "localPart": "biden", "forwardTo": "joe@gmail.com" } - forwardTo is optional — omit for programmatic-only mailbox (retainMessages auto-enabled) - Max 100 inboxes per subdomain, 500 messages per inbox - Returns: { "success": true, "inbox": "biden@craig.x402email.com", "retainMessages": true, "messageLimit": 500 } ### POST /api/subdomain/inbox/list — List subdomain inboxes - Protection: SIWX wallet proof only (free, no payment) - Only the subdomain owner can list - Body: { "subdomain": "craig" } - Returns: { "success": true, "inboxes": [{ "localPart": "string", "address": "string", "forwardTo": "string?", "retainMessages": bool, "active": bool, "messageCount": number, "unreadCount": number }] } ### POST /api/subdomain/inbox/update — Update inbox settings - Protection: SIWX wallet proof only (free, no payment) - Only the subdomain owner can update - Body: { "subdomain": "craig", "localPart": "biden", "forwardTo": "newemail@example.com", "retainMessages": true } - At least one of "forwardTo" or "retainMessages" is required - Set forwardTo to null to remove forwarding - Returns: { "success": true, "inbox": "biden@craig.x402email.com", "forwardTo": "string?", "retainMessages": bool } ### POST /api/subdomain/inbox/delete — Delete inbox from subdomain - Protection: SIWX wallet proof only (free, no payment) - Only the subdomain owner can delete - Body: { "subdomain": "craig", "localPart": "biden" } - Cascades: deletes all messages from DB and S3 - Returns: { "success": true, "deleted": "biden@craig.x402email.com", "messagesDeleted": number } ### POST /api/subdomain/inbox/messages — List inbox messages - Protection: x402 payment ($0.001 USDC on Base) - Payer wallet must be the subdomain owner - Body: { "subdomain": "craig", "localPart": "biden", "cursor": "message id (optional)", "limit": 20 } - Returns: { "success": true, "messages": [...], "nextCursor": "string?", "messageCount": number, "messageLimit": 500, "warning": "string?" } - Warning field appears when inbox is at or near capacity (>=80%). Delete old messages to free space. ### POST /api/subdomain/inbox/messages/read — Read a single message - Protection: x402 payment ($0.001 USDC on Base) - Payer wallet must be the subdomain owner - Body: { "messageId": "string" } - Returns: { "success": true, "message": { "id": "string", "from": "string", "to": ["string"], "subject": "string", "date": "ISO date", "text": "string", "html": "string", "attachments": [{ "filename": "string", "contentType": "string", "size": number }], "receivedAt": "ISO date" } } - Marks the message as read ### POST /api/subdomain/inbox/messages/delete — Delete a message - Protection: SIWX wallet proof only (free, no payment) - Only the subdomain owner can delete messages - Body: { "messageId": "string" } - Returns: { "success": true, "deleted": "string" } ## Forwarding Inbox Buy `username@x402email.com` for $1/month. Use it as a forwarding inbox (emails forwarded to your real address), a programmatic mailbox (read messages via API), or both. You can also send from your inbox address. Duration-based pricing with bulk discounts. Anyone can top up any inbox. Cancel anytime for a pro-rata refund. ### POST /api/inbox/buy — Buy an inbox ($1, 30 days) - Protection: x402 payment ($1 USDC on Base) - Body: { "username": "alice", "forwardTo": "alice@gmail.com" } - forwardTo is optional — omit it to use as a programmatic mailbox (retainMessages enabled automatically, read messages via /api/inbox/messages) - Username rules: 3-30 chars, lowercase alphanumeric + hyphens - Subdomain owners can buy the matching inbox name (e.g., owner of alice.x402email.com can buy alice@x402email.com) - Returns: { "success": true, "inbox": "alice@x402email.com", "retainMessages": true, "expiresAt": "ISO date", "daysRemaining": 30 } ### POST /api/inbox/topup — Top up inbox 30 days ($1) - Protection: x402 payment ($1 USDC) - Anyone can top up any inbox — no SIWX required - Body: { "username": "alice" } - Returns: { "success": true, "inbox": "alice", "expiresAt": "ISO date", "daysRemaining": number, "daysAdded": 30 } ### POST /api/inbox/topup/quarter — Top up inbox 90 days ($2.50, save 17%) - Protection: x402 payment ($2.50 USDC) - Anyone can top up any inbox — no SIWX required - Body: { "username": "alice" } - Returns: { "success": true, "inbox": "alice", "expiresAt": "ISO date", "daysRemaining": number, "daysAdded": 90 } ### POST /api/inbox/topup/year — Top up inbox 365 days ($8, save 34%) - Protection: x402 payment ($8 USDC) - Anyone can top up any inbox — no SIWX required - Body: { "username": "alice" } - Returns: { "success": true, "inbox": "alice", "expiresAt": "ISO date", "daysRemaining": number, "daysAdded": 365 } ### POST /api/inbox/send — Send from your inbox address ($0.005) - Protection: x402 payment ($0.005 USDC) - Payer wallet must be the inbox owner - Body: { "username": "alice", "to": ["bob@example.com"], "subject": "Hello", "html": "
Hi
", "text": "Hi", "replyTo": "alice@gmail.com" } - Requires either "html" or "text" (or both) - Returns: { "success": true, "messageId": "string", "from": "alice@x402email.com" } ### GET /api/inbox/status?username=alice — Check inbox status - Protection: SIWX wallet proof only (free, no payment) - Only the inbox owner can check status - Returns: { "inbox": "alice@x402email.com", "ownerWallet": "0x...", "forwardTo": "email", "retainMessages": bool, "expiresAt": "ISO date", "daysRemaining": number, "daysOwned": number, "active": bool, "pricing": {...} } ### POST /api/inbox/update — Update inbox settings - Protection: SIWX wallet proof only (free, no payment) - Only the inbox owner can update - Body: { "username": "alice", "forwardTo": "newemail@example.com", "retainMessages": true } - At least one of "forwardTo" or "retainMessages" is required - "retainMessages": when true, inbound emails are kept in S3 for programmatic access via the messages API - Returns: { "success": true, "inbox": "alice@x402email.com", "forwardTo": "newemail@example.com", "retainMessages": true } ### POST /api/inbox/cancel — Cancel inbox and get pro-rata USDC refund - Protection: SIWX wallet proof only (free, no payment) - Only the inbox owner can cancel - Body: { "username": "alice" } - Refund is sent on-chain to the caller's wallet automatically - Refunds below $0.01 are waived (too small to transfer) - Returns: { "success": true, "inbox": "alice@x402email.com", "cancelled": true, "refund": { "amount": "0.50", "currency": "USDC", "network": "eip155:8453", "to": "0x...", "status": "completed", "transactionHash": "0x..." }, "daysRemaining": 15 } ## Inbox Messages API Read inbound emails programmatically. Requires "retainMessages": true on the inbox (set via POST /api/inbox/update). ### POST /api/inbox/messages — List messages - Protection: x402 payment ($0.001 USDC on Base) - Payer wallet must be the inbox owner - Body: { "username": "alice", "cursor": "message id (optional)", "limit": 20 } - Returns: { "success": true, "messages": [{ "id": "string", "fromEmail": "string", "subject": "string", "receivedAt": "ISO date", "read": bool }], "nextCursor": "message id (optional)" } - Paginated: pass "nextCursor" as "cursor" in the next request ### POST /api/inbox/messages/read — Read a single message - Protection: x402 payment ($0.001 USDC on Base) - Payer wallet must be the inbox owner - Body: { "messageId": "string" } - Returns: { "success": true, "message": { "id": "string", "from": "string", "to": ["string"], "subject": "string", "date": "ISO date", "text": "string", "html": "string", "attachments": [{ "filename": "string", "contentType": "string", "size": number }], "receivedAt": "ISO date" } } - Marks the message as read ### POST /api/inbox/messages/delete — Delete a message - Protection: SIWX wallet proof only (free, no payment) - Only the inbox owner can delete messages - Body: { "messageId": "string" } - Removes the message from DB and S3 storage - Returns: { "success": true, "deleted": "string" } ## Images in Emails To include images, use `