API Reference

MailAPI API Reference

Build domains, provision mailboxes, and track queue jobs using MailAPI endpoints.

Authentication & Conventions

Use header-based authentication only: Authorization: Bearer <key> or X-Api-Key: <key>.

Base URL

https://mailapi.tech/api

API Key Format

32 characters (alpha-numeric)

Queue Behavior

Work that runs in the background returns a `task_id`. Poll the matching get-task endpoint for that operation (see the Endpoints list) until `status` is `completed` or `failed`. Bulk domain deletes accept up to 10 hostnames per request; bulk mailbox deletes accept up to 100 addresses; both follow the same task pattern. Each bulk-delete type allows only one successfully queued request every 5 minutes for a given API key and client IP together; validation errors (HTTP 422) do not count toward that limit. Creating resources and running bulk deletes requires an active pricing plan (admin accounts are exempt).

Success Contract

{
    "status": "success"
}

Error Contract

{
    "status": "error",
    "reason": "Error description"
}
POST /api/v1/create/domain

Create Domain

Creates a new base domain in your MailAPI workspace and queues provisioning in the background.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
Domain string Yes Fully qualified hostname (e.g. example.com). Omit http(s)://; single-label names are rejected (same rules as the dashboard Add domain form).
Params object No Optional keys (for example `total_mailbox_allowed`).
Params.total_mailbox_allowed integer No Mailbox slots recorded for the domain (minimum 1, maximum 100; defaults to the app maximum per hostname).

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/create/domain') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Domain": "example.com",
    "Params": {
      "total_mailbox_allowed": 100
    }
  }'

Success Response

{
    "status": "success",
    "domain": "example.com",
    "task_id": 101
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - An active pricing plan is required before you can create domains, subdomains, or mailboxes via the API.
  • HTTP 409 - Domain already exists for this account.
  • HTTP 422 - First validation error message (invalid body fields).

Notes

  • Invalid hostnames return HTTP 422 before enqueue; duplicates return HTTP 409.
  • Poll `GET /api/v1/get/domain?task_id=…`. When `completed`, `results` includes DNS `records` (MX/TXT/A).
  • Remote mail server defaults apply on provision; quota fields are not accepted on this request.
GET /api/v1/get/domain?task_id={task_id}

Get Domain Task

Polls a root domain create task created by `POST /api/v1/create/domain`.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
task_id integer Yes Task identifier returned by Create Domain.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/get/domain') }}?task_id=101" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "Task_id": 101,
    "total_email": 0,
    "domain": "example.com",
    "results": {
        "domain": "example.com",
        "status": "Created successfully.",
        "records": [
            {
                "type": "MX",
                "name": "example.com",
                "value": "mail.mailapi.tech",
                "priority": "10",
                "status": "Not checked"
            },
            {
                "type": "TXT",
                "name": "_mailapi.example.com",
                "value": "<generated-unique-token>",
                "priority": "\u2014",
                "status": "Not checked"
            },
            {
                "type": "A",
                "name": "mail.example.com",
                "value": "157.230.159.61",
                "priority": "\u2014",
                "status": "Not checked"
            }
        ]
    },
    "status": "completed",
    "task_id": "101"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Task ID was not found for this API key.
  • HTTP 422 - Task type does not match this endpoint.
  • HTTP 422 - Dynamic failure message from the queue job (same shape as other errors).

Notes

  • `status` may be `queued`, `running`, `completed`, or `failed`. Only `failed` returns HTTP 422 with `reason` from the task.
  • While `queued` or `running`, `results` is often an empty array until the job finishes.
  • Responses include `Task_id` (integer) and `task_id` (same value as a string).
POST /api/v1/create/sub-domain

Create Sub-Domain Batch

Creates up to 10 sub-domains under an existing parent domain in a single queued task.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
Domain string Yes Existing parent (root) domain owned by your account. Must be a valid dotted hostname (same rules as Create Domain / dashboard).
Params.sub_domains string[] Yes Sub-domain labels (not FQDN), max 10 per request.
Params.total_mailbox_allowed integer No Mailbox slots per created hostname (min 1, max 100; defaults to the app maximum per hostname).

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/create/sub-domain') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Domain": "example.com",
    "Params": {
      "sub_domains": ["team", "support", "billing"]
    }
  }'

Success Response

{
    "status": "success",
    "domain": "example.com",
    "task_id": 202
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - An active pricing plan is required before you can create domains, subdomains, or mailboxes via the API.
  • HTTP 404 - Parent domain was not found.
  • HTTP 422 - Params.sub_domains must be a non-empty array (or validation on labels).
  • HTTP 422 - Maximum 10 sub-domains are allowed per request.
  • HTTP 429 - Sub-domain requests are limited to once per 5 minutes for this domain and API key.

Notes

  • After a successful run: at most one request per 5 minutes per API key and parent domain.
  • Poll `GET /api/v1/get/sub-domain?task_id=…`. When `completed`, nested `results` are keyed by FQDN.
  • Provisioning uses the same remote defaults as Create Domain; quota fields are not accepted.
GET /api/v1/get/sub-domain?task_id={task_id}

Get Sub-Domain Task

Polls a sub-domain batch task from `POST /api/v1/create/sub-domain`.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
task_id integer Yes Task identifier returned by Create Sub-Domain.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/get/sub-domain') }}?task_id=202" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "Task_id": 202,
    "total_email": 0,
    "domain": "example.com",
    "results": {
        "domain": "example.com",
        "results": {
            "team.example.com": {
                "status": "Created successfully.",
                "records": [
                    {
                        "type": "MX",
                        "name": "team.example.com",
                        "value": "mail.mailapi.tech",
                        "priority": "10",
                        "status": "Not checked"
                    }
                ]
            },
            "support.example.com": {
                "status": "Created successfully.",
                "records": [
                    {
                        "type": "MX",
                        "name": "support.example.com",
                        "value": "mail.mailapi.tech",
                        "priority": "10",
                        "status": "Not checked"
                    }
                ]
            }
        }
    },
    "status": "completed",
    "task_id": "202"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Task ID was not found for this API key.
  • HTTP 422 - Task type does not match this endpoint.
  • HTTP 422 - Dynamic failure message from provisioning.

Notes

  • `status` values are the same as other task endpoints (`queued`, `running`, `completed`, `failed`).
  • Responses include `Task_id` (integer) and `task_id` (same value as a string).
GET /api/v1/list/domain

List Domains

Returns all domains for the API key owner account, keyed by domain name.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/list/domain') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "total_domain": 2,
    "results": {
        "example.com": {
            "status": "verified",
            "domain_type": "root",
            "domain_quota": "0GB",
            "mailbox_count": "15",
            "created_at": "14-04-2026"
        },
        "team.example.com": {
            "status": "verified",
            "domain_type": "sub",
            "domain_quota": "0GB",
            "mailbox_count": "3",
            "created_at": "15-04-2026"
        }
    },
    "status": "success"
}

Error Responses

  • HTTP 401 - Invalid API key.

Notes

  • `domain_type` is `root` or `sub`.
  • `domain_quota` is a string with a `GB` suffix; `0GB` means unlimited in list responses (non-zero may appear on older rows).
POST /api/v1/create/mailbox/single

Create Single Mailbox

Queues one mailbox creation request for a domain that belongs to your account.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
Email_fullname string Yes Display name stored on the mailbox (not the email local-part).
single_bulk string Yes Must be `single`.
Domain string Yes Target domain hostname.
Params object Yes Payload object for mailbox provisioning details.
Params.email_id string Yes Mailbox address. Must belong to the provided Domain.
Params.password string|integer Yes Mailbox password string (minimum 8 characters) or numeric `0` to auto-generate a secure password (20+ chars).

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/create/mailbox/single') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Email_fullname": "John Doe",
    "single_bulk": "single",
    "Domain": "example.com",
    "Params": {
      "email_id": "john@example.com",
      "password": 0
    }
  }'

Success Response

{
    "status": "success",
    "task_id": 123
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - An active pricing plan is required before you can create domains, subdomains, or mailboxes via the API.
  • HTTP 404 - Domain not found for this account.
  • HTTP 422 - First validation error message (invalid body fields).

Notes

  • Invalid bodies return HTTP 422 before enqueue. Only numeric `0` for `Params.password` triggers auto-generation (string `"0"` is rejected).
  • Poll `GET /api/v1/get/mailbox/single?task_id=…`; remote failures return HTTP 422 on that poll.
POST /api/v1/create/mailbox/bulk

Create Bulk Mailboxes

Queues a bulk mailbox provisioning task and returns a task ID for later retrieval.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
Email_fullname string Yes Display name used with internal rules to derive unique mailbox local-parts.
single_bulk string Yes Must be `bulk`.
Domain string Yes Target domain hostname.
Params object Yes Payload object for mailbox provisioning details.
Params.mailbox_no integer Yes How many mailboxes to create (must be between 1 and 100).
Params.password string|integer Yes Shared password string for the batch (minimum 8 characters), or numeric `0` to generate a unique secure password (20+ chars) per mailbox.

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/create/mailbox/bulk') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Email_fullname": "Team Member",
    "single_bulk": "bulk",
    "Domain": "example.com",
    "Params": {
      "mailbox_no": 25,
      "password": 0
    }
  }'

Success Response

{
    "status": "success",
    "task_id": 456
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - An active pricing plan is required before you can create domains, subdomains, or mailboxes via the API.
  • HTTP 404 - Domain not found for this account.
  • HTTP 422 - First validation error message (invalid body fields).
  • HTTP 429 - Bulk mailbox requests are limited to once per 5 minutes for this domain and API key.

Notes

  • After a successful run: at most one bulk create per 5 minutes per API key and target hostname.
  • `Params.mailbox_no` must be between 1 and 100.
  • If a generated mailbox address already exists, it is skipped and the task continues creating the remaining addresses.
  • If all requested addresses already exist, the task still completes successfully with `total_email` set to `0` and an empty `results` object.
  • Only numeric `0` for `Params.password` triggers per-mailbox auto-generation (string `"0"` is rejected).
  • Poll `GET /api/v1/get/mailbox/bulk?task_id=…`; remote failures return HTTP 422 on that poll.
GET /api/v1/get/mailbox/single?task_id={task_id}

Get Single Mailbox Task

Fetches status and final result for a single mailbox provisioning task.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
task_id integer Yes Task identifier returned by create endpoint.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/get/mailbox/single') }}?task_id=123" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "Task_id": 123,
    "total_email": 1,
    "domain": "example.com",
    "results": {
        "john@example.com": {
            "email": "john@example.com",
            "password": "SecurePass123",
            "quota": "0MB",
            "domain": "example.com",
            "provisioning": "pending",
            "create_date": "2026-04-26 16:45:00"
        }
    },
    "status": "completed",
    "task_id": "123"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Task ID was not found for this API key.
  • HTTP 422 - Task type does not match this endpoint.
  • HTTP 422 - Dynamic failure message from `error_message` when the task fails.

Notes

  • `status` is `queued`, `running`, `completed`, or `failed`. While pending, `results` is often empty.
  • Both `Task_id` (int) and `task_id` (string) are returned with the same value.
  • When `completed`, each entry includes `email`, `password`, `quota`, `domain`, `provisioning`, `create_date` (no per-entry `status`).
  • If create used `Params.password: 0`, the response `password` is generated per mailbox.
GET /api/v1/get/mailbox/bulk?task_id={task_id}

Get Bulk Mailbox Task

Fetches status and per-mailbox results for a bulk mailbox provisioning task.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
task_id integer Yes Task identifier returned by bulk create endpoint.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/get/mailbox/bulk') }}?task_id=456" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "Task_id": 456,
    "total_email": 25,
    "domain": "example.com",
    "results": {
        "team1@example.com": {
            "status": "Created successfully.",
            "password": "kL4!pQ9#uD2@xM7&zT8w"
        },
        "team2@example.com": {
            "status": "Created successfully.",
            "password": "rN6$hS1*eV0!cB3%yK5m"
        }
    },
    "status": "completed",
    "task_id": "456"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Task ID was not found for this API key.
  • HTTP 422 - Task type does not match this endpoint.
  • HTTP 422 - Dynamic failure message from `error_message` when the task fails.

Notes

  • `status` follows the same lifecycle as single mailbox tasks.
  • Responses include `Task_id` (integer) and `task_id` (same value as a string).
  • When some requested addresses already exist, those addresses are skipped and `total_email` reflects only newly created mailboxes.
  • If all requested addresses already exist, the task still completes successfully with `total_email` set to `0` and an empty `results` object.
  • Results include mailbox-by-mailbox status details when `completed`.
  • If bulk create used numeric `Params.password: 0`, each mailbox result includes its own generated `password` value.
POST /api/v1/delete/domain/bulk

Bulk Delete Domains

Queues removal of up to 10 domains (root or sub-domain hostnames) owned by your account. Deletes run sequentially on the mail server; there is no artificial delay between items.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key` with `write` permission.

Field Type Required Description
Domains string[] Yes Fully qualified hostnames to remove (1–10 per request). Duplicates are rejected. Same hostname rules as create domain (no scheme; valid dotted hostname).

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/delete/domain/bulk') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Domains": ["old.example.com", "legacy.example.com"]
  }'

Success Response

{
    "status": "success",
    "task_id": 801
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - An active pricing plan is required before you can create, bulk-delete, or manage domains, subdomains, or mailboxes via the API.
  • HTTP 422 - Validation error (empty array, too many domains, invalid hostname, or duplicate entries).
  • HTTP 429 - Too many requests (bulk domain delete is limited to one successfully enqueued call per 5 minutes per API key and IP).

Notes

  • Cooldown: one successfully enqueued call per 5 minutes per API key and IP; HTTP 422 does not count. Mailbox bulk delete uses a separate counter of the same length.
  • Poll `GET /api/v1/get/delete/domain/bulk?task_id=…` until `completed` or `failed`.
  • When `completed`, `results` entries use `deleted`, `failed`, or `skipped` with optional `reason`; partial failures still yield task `completed`.
  • Deleting a root domain removes descendant hostnames and their mailboxes in dependency order.
GET /api/v1/get/delete/domain/bulk?task_id={task_id}

Get Bulk Delete Domains Task

Polls a bulk domain delete task created by `POST /api/v1/delete/domain/bulk`.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key` with `read` permission.

Field Type Required Description
task_id integer Yes Task identifier returned by Bulk Delete Domains.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/get/delete/domain/bulk') }}?task_id=801" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "Task_id": 801,
    "total_email": 0,
    "domain": "old.example.com",
    "results": {
        "old.example.com": {
            "status": "deleted"
        },
        "legacy.example.com": {
            "status": "failed",
            "reason": "Mail server rejected domain removal."
        },
        "missing.example.com": {
            "status": "skipped",
            "reason": "Domain not found for this account."
        }
    },
    "status": "completed",
    "task_id": "801"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Task ID was not found for this API key.
  • HTTP 422 - Task type does not match this endpoint.
  • HTTP 422 - Dynamic failure message from `error_message` when the task fails.

Notes

  • `status` may be `queued`, `running`, `completed`, or `failed`. Only `failed` (task-level) returns HTTP 422 with `reason` from the task.
  • Per-domain outcomes (`deleted`, `failed`, or `skipped`) appear inside `results` while the overall task can still be `completed`.
POST /api/v1/delete/mailbox/bulk

Bulk Delete Mailboxes

Queues removal of up to 100 mailbox addresses owned by your account. Deletes run sequentially; there is no artificial delay between items.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key` with `write` permission.

Field Type Required Description
Mailboxes string[] Yes Full RFC email addresses (1–100 per request). Duplicates are rejected.

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/delete/mailbox/bulk') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "Mailboxes": ["a@example.com", "b@example.com"]
  }'

Success Response

{
    "status": "success",
    "task_id": 802
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - An active pricing plan is required before you can create, bulk-delete, or manage domains, subdomains, or mailboxes via the API.
  • HTTP 422 - Validation error (empty array, too many addresses, invalid email, or duplicate entries).
  • HTTP 429 - Too many requests (bulk mailbox delete is limited to one successfully enqueued call per 5 minutes per API key and IP).

Notes

  • Cooldown: one successfully enqueued call per 5 minutes per API key and IP; HTTP 422 does not count. Domain bulk delete uses a separate counter of the same length.
  • Poll `GET /api/v1/get/delete/mailbox/bulk?task_id=…` until `completed` or `failed`.
  • When `completed`, `results` entries use `deleted`, `failed`, or `skipped` with optional `reason`.
GET /api/v1/get/delete/mailbox/bulk?task_id={task_id}

Get Bulk Delete Mailboxes Task

Polls a bulk mailbox delete task created by `POST /api/v1/delete/mailbox/bulk`.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key` with `read` permission.

Field Type Required Description
task_id integer Yes Task identifier returned by Bulk Delete Mailboxes.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/get/delete/mailbox/bulk') }}?task_id=802" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "Task_id": 802,
    "total_email": 2,
    "domain": "example.com",
    "results": {
        "a@example.com": {
            "status": "deleted"
        },
        "b@example.com": {
            "status": "failed",
            "reason": "Mail server rejected mailbox removal."
        },
        "gone@example.com": {
            "status": "skipped",
            "reason": "Mailbox not found for this account."
        }
    },
    "status": "completed",
    "task_id": "802"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Task ID was not found for this API key.
  • HTTP 422 - Task type does not match this endpoint.
  • HTTP 422 - Dynamic failure message from `error_message` when the task fails.

Notes

  • `total_email` mirrors the request size (count of addresses submitted), not the number successfully deleted.
  • Per-mailbox outcomes (`deleted`, `failed`, or `skipped`) appear inside `results` while the overall task can still be `completed`.
GET /api/v1/list/mailbox?domain={domain}&include_credentials={0|1}

List Mailboxes

Returns all mailboxes for a specific owned domain, keyed by full email address.

Header auth required: `Authorization: Bearer <key>` or `X-Api-Key`.

Field Type Required Description
domain string Yes Domain to list mailboxes for.
include_credentials boolean No Include `imap_credentials` in each mailbox result when true.

Request Example

curl --fail-with-body --silent --show-error \
  "{{ url('/api/v1/list/mailbox') }}?domain=example.com&include_credentials=1" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "domain": "example.com",
    "results": {
        "john@example.com": {
            "provisioning_status": "active",
            "mailbox_quota": "0MB",
            "imap_credentials": {
                "host": "imap.example.com",
                "port": 993,
                "encryption": "tls"
            },
            "created_at": "14-04-2026"
        }
    },
    "status": "success"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Domain not found for this account.

Notes

  • `imap_credentials` only when `include_credentials=true`.
  • `mailbox_quota` is a string with an `MB` suffix; `0MB` means unlimited (non-zero may appear on older rows).
POST /api/v1/mail/inbound

Inbound Email

Accepts inbound payloads for a tenant mailbox and queues processing. Optional fields include `from_name`, `cc`, `bcc`, `body_html`, `attachments`, and `headers`.

Requires API key with `inbound` permission.

Field Type Required Description
message_id string Yes Upstream message identifier. Must be unique per mailbox.
from_email string Yes Sender email address.
to_email string Yes Recipient mailbox address owned by your tenant.
subject string Yes Email subject line.
received_at ISO datetime Yes Inbound receive timestamp.

Request Example

curl --fail-with-body --silent --show-error \
  -X POST "{{ url('/api/v1/mail/inbound') }}" \
  -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message_id": "<mail-message-id>",
    "from_email": "sender@example.com",
    "to_email": "user@example.com",
    "subject": "Hello",
    "body_text": "Body",
    "received_at": "2026-04-28T10:00:00Z"
  }'

Success Response

{
    "status": "accepted",
    "message_id": "<mail-message-id>"
}

Error Responses

  • HTTP 401 - API key is required or invalid.
  • HTTP 403 - API key lacks inbound permission.
  • HTTP 409 - Duplicate message_id.
  • HTTP 422 - Unknown mailbox or invalid payload.

Notes

  • Inbound processing is asynchronous.
GET /api/v1/emails

List Emails

Returns tenant-scoped inbox emails with cursor pagination.

Requires API key with `read` permission.

Field Type Required Description
mailbox_id integer No Filter by mailbox.
unread boolean No Return unread only.
since ISO datetime No Filter received_at lower bound.
before ISO datetime No Filter received_at upper bound.

Request Example

curl "{{ url('/api/v1/emails?unread=1') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "data": [],
    "meta": {
        "next_cursor": null,
        "prev_cursor": null
    }
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks read permission.

Notes

  • Query is always tenant-isolated.
GET /api/v1/emails/{email}

Get Email

Returns one tenant-scoped email with attachment metadata.

Requires API key with `read` permission.

Field Type Required Description
email integer Yes Email record ID (route parameter `{email}`).

Request Example

curl "{{ url('/api/v1/emails/123') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "data": {
        "id": 123
    }
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Email not found in your tenant scope.

Notes

  • Soft-deleted records are not returned from this endpoint.
GET /api/v1/emails/sync?since=ISO_TIMESTAMP

Sync Emails

Incremental polling endpoint for new, updated, and deleted emails.

Requires API key with `read` permission.

Field Type Required Description
since ISO datetime Yes Sync lower bound using updated markers.

Request Example

curl "{{ url('/api/v1/emails/sync?since=2026-04-28T00:00:00Z') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "data": [],
    "meta": {
        "next_cursor": null,
        "prev_cursor": null
    }
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 422 - The since field is required and must be a valid date.

Notes

  • Deleted emails are returned with deletion markers to support tombstones.
POST /api/v1/emails/{email}/read

Mark Email Read

Marks an email as read and emits an email.read webhook event.

Requires API key with `write` permission.

Field Type Required Description
email integer Yes Email record ID (route parameter `{email}`).

Request Example

curl -X POST "{{ url('/api/v1/emails/123/read') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "status": "success"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks write permission.
  • HTTP 404 - Email not found in your tenant scope.

Notes

  • This endpoint is idempotent.
DELETE /api/v1/emails/{email}

Delete Email

Soft-deletes an email and emits an email.deleted webhook event.

Requires API key with `write` permission.

Field Type Required Description
email integer Yes Email record ID (route parameter `{email}`).

Request Example

curl -X DELETE "{{ url('/api/v1/emails/123') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "status": "success"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks write permission.
  • HTTP 404 - Email not found in your tenant scope.

Notes

  • Record is soft deleted, not permanently removed.
GET /api/v1/emails/{email}/attachments/{attachment}

Attachment URL

Returns a temporary signed attachment download URL.

Requires API key with `read` permission.

Field Type Required Description
email integer Yes Email record ID (route parameter `{email}`).
attachment integer Yes Attachment record ID (route parameter `{attachment}`).

Request Example

curl "{{ url('/api/v1/emails/123/attachments/456') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "data": {
        "url": "https://signed-url",
        "expires_at": "2026-04-28T10:10:00Z"
    }
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 404 - Email or attachment not found in your tenant scope.

Notes

  • URL expires shortly after issuance.
POST /api/v1/webhooks

Register Webhook

Creates a tenant-scoped webhook target for email events.

Requires API key with `webhook` permission.

Field Type Required Description
url url Yes Destination webhook URL.
events array Yes Allowed values: email.received, email.read, email.deleted.

Request Example

curl -X POST "{{ url('/api/v1/webhooks') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" -H "Content-Type: application/json" -d '{"url":"https://example.com/hook","events":["email.received"]}'

Success Response

{
    "data": {
        "id": 1
    }
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks webhook permission.
  • HTTP 422 - Invalid URL or event selection.

Notes

  • Deliveries are queued and signed using the webhook secret and timestamp headers.
GET /api/v1/webhooks

List Webhooks

Returns tenant-scoped webhook endpoints.

Requires API key with `webhook` permission.

Field Type Required Description

Request Example

curl "{{ url('/api/v1/webhooks') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "data": [
        {
            "id": 1,
            "url": "https://example.com/hook",
            "events": [
                "email.received"
            ],
            "is_active": true
        }
    ]
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks webhook permission.

Notes

  • Each row includes `last_triggered_at` when the webhook has fired.
PATCH /api/v1/webhooks/{webhook}

Update Webhook

Updates URL, events, or active state.

Requires API key with `webhook` permission.

Field Type Required Description
webhook integer Yes Webhook ID (route parameter `{webhook}`).
url url No Destination webhook URL.
events array No Allowed values: email.received, email.read, email.deleted.
is_active boolean No Whether webhook should receive deliveries.

Request Example

curl -X PATCH "{{ url('/api/v1/webhooks/1') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY" -H "Content-Type: application/json" -d '{"is_active":false}'

Success Response

{
    "status": "success"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks webhook permission.
  • HTTP 404 - Webhook not found in your tenant scope.
  • HTTP 422 - Invalid URL or event selection.

Notes

  • Include at least one of `url`, `events`, or `is_active`.
DELETE /api/v1/webhooks/{webhook}

Delete Webhook

Deletes a tenant webhook endpoint.

Requires API key with `webhook` permission.

Field Type Required Description
webhook integer Yes Webhook ID (route parameter `{webhook}`).

Request Example

curl -X DELETE "{{ url('/api/v1/webhooks/1') }}" -H "Authorization: Bearer YOUR_32_CHARACTER_API_KEY"

Success Response

{
    "status": "success"
}

Error Responses

  • HTTP 401 - Invalid API key.
  • HTTP 403 - API key lacks webhook permission.
  • HTTP 404 - Webhook not found in your tenant scope.

Notes

  • Permanent delete; queued delivery rows for this webhook are removed.