API Documentation

Public REST API only — create inboxes, read mail, manage messages. Prefer v1 + API token for new integrations. Domain list and create endpoints only use public domains.

API v1 /api/v1/*

Token-based API. Create an inbox (or generate a token from the web UI) and call endpoints with the API token.

Authentication

Send the API token as a Bearer token. Tokens look like am_at_…. You get one automatically from POST /api/v1/inbox, or create more from the inbox UI (API tab).

Authorization: Bearer am_at_xxxxxxxxxxxxxxxx

Rate limits

25 requests/second per inbox (API token). Over limit → 429 with Retry-After. Successful responses include X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

Response format

// Success
{ "success": true, "data": { ... } }

// List + pagination
{
  "success": true,
  "data": [ ... ],
  "pagination": { "page": 1, "limit": 50, "total": 42, "totalPages": 1 }
}

// Error
{ "success": false, "error": "Error message" }

Endpoints

POST
/api/v1/inbox

Create a permanent inbox on a public domain (optional username/password). Returns email, password, web token, and apiToken.

public
GET
/api/v1/inbox

Get current inbox info (email, emailCount, storageUsed, createdAt)

API token
DELETE
/api/v1/inbox

Delete inbox and all emails

API token
GET
/api/v1/emails

List non-expired emails. Query: ?page=1&limit=50 (limit max 100)

API token
GET
/api/v1/emails/:id

Get full email (bodyHtml, bodyText, attachments). Marks as read.

API token
DELETE
/api/v1/emails/:id

Delete one email

API token
GET
/api/v1/emails/:id/attachments/:attId

Download attachment (raw file bytes)

API token

Example: full flow (v1)

# 1. Create inbox (public) — optional username/password
curl -X POST https://amail.my/api/v1/inbox \
  -H "Content-Type: application/json" \
  -d '{"username":"myapp","password":"secret"}'

# Response 201:
# {
#   "success": true,
#   "data": {
#     "email": "[email protected]",
#     "token": "<web-inbox-token>",
#     "password": "secret",
#     "apiToken": "am_at_..."
#   }
# }

# 2. List emails
curl "https://amail.my/api/v1/emails?page=1&limit=50" \
  -H "Authorization: Bearer am_at_..."

# 3. Get one email
curl https://amail.my/api/v1/emails/<EMAIL_ID> \
  -H "Authorization: Bearer am_at_..."

# 4. Download attachment
curl -OJ https://amail.my/api/v1/emails/<EMAIL_ID>/attachments/<ATT_ID> \
  -H "Authorization: Bearer am_at_..."

# 5. Delete email
curl -X DELETE https://amail.my/api/v1/emails/<EMAIL_ID> \
  -H "Authorization: Bearer am_at_..."

# 6. Inbox info / delete inbox
curl https://amail.my/api/v1/inbox \
  -H "Authorization: Bearer am_at_..."
curl -X DELETE https://amail.my/api/v1/inbox \
  -H "Authorization: Bearer am_at_..."

Create inbox body

POST /api/v1/inbox
{
  "username": "optional",   // a-zA-Z0-9, max 64; default: random
  "password": "optional"    // default: auto-generated
}
// Uses the default public domain (e.g. amail.my).
// Private domains are not available via this API.

JWT account API legacy-style

Address + password → short-lived JWT. Responses use a Hydra-like shape (compatible with some MailTM-style clients). Prefer API v1 for new apps.

Authentication

Create an account, then exchange credentials for a JWT (valid 24 hours). Use it on message endpoints:

# Login
curl -X POST https://amail.my/api/token \
  -H "Content-Type: application/json" \
  -d '{"address":"[email protected]","password":"secret"}'

# → { "token": "eyJ...", "id": "...", "address": "[email protected]" }

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

Response format (Hydra-style)

This API does not use success/data.

// Domain / message lists
{
  "hydra:member": [ { "@id": "...", ... } ],
  "hydra:totalItems": 42,
  "page": 1,
  "limit": 50,
  "totalPages": 1
}

// Create account 201
{ "@id": "...", "address": "[email protected]", "createdAt": "..." }

// Token
{ "token": "eyJ...", "id": "...", "address": "[email protected]" }

// Single message
{
  "@id": "...",
  "from": { "address": "...", "name": "" },
  "to": [{ "address": "..." }],
  "subject": "...",
  "html": ["..."],
  "text": "...",
  "hasAttachments": false,
  "attachments": [],
  "size": 1234,
  "isRead": true,
  "createdAt": "..."
}

// Errors
{ "detail": "Error message" }

Rate limits

No per-second rate limit on JWT message routes (unlike v1). Still use reasonable request rates.

Endpoints

GET
/api/domains

List public domains only (active + shared). Hydra collection.

public
POST
/api/accounts

Create inbox on a public domain (address + password, permanent)

public
POST
/api/token

Exchange address + password for JWT (24h)

public
GET
/api/messages

List non-expired messages. Query: ?page=1 (limit fixed at 50)

JWT
GET
/api/messages/:id

Get single message with body + attachments

JWT
DELETE
/api/messages/:id

Delete a message

JWT

Example: full flow (JWT)

# 1. Public domains only
curl https://amail.my/api/domains

# 2. Create account (address must use a public domain from step 1)
curl -X POST https://amail.my/api/accounts \
  -H "Content-Type: application/json" \
  -d '{"address":"[email protected]","password":"secret"}'

# 3. JWT
curl -X POST https://amail.my/api/token \
  -H "Content-Type: application/json" \
  -d '{"address":"[email protected]","password":"secret"}'

# 4. List messages (?page only; limit is always 50)
curl "https://amail.my/api/messages?page=1" \
  -H "Authorization: Bearer <JWT>"

# 5. Get / delete message
curl https://amail.my/api/messages/<ID> \
  -H "Authorization: Bearer <JWT>"
curl -X DELETE https://amail.my/api/messages/<ID> \
  -H "Authorization: Bearer <JWT>"

HTTP status codes

  • 200 OK · 201 Created
  • 401 Unauthorized · 404 Not found
  • 409 Conflict (v1 username taken) · 422 Validation (JWT accounts)
  • 429 Rate limited (v1 only)

Base URL: https://amail.my

GET /api/domains returns only domains marked public. Messages expire per domain TTL (default 2 hours) and are omitted from list/get after expiry.