AxeneAxene Docs
API Reference

Emails API

Complete API reference for sending, listing, searching, scheduling, and retrying emails in Axene Mailer.

Base URL: https://mail.axene.io/v1

All endpoints require authentication via API Key or JWT cookie. API keys are passed as Authorization: Bearer axm_k_....

Using an official SDK? The emails resource wraps every endpoint below. Guides: TypeScript, Python, Go, PHP, Ruby, Rust, Java, .NET, Swift.


Send an email

POST /v1/emails/

Send a single email. Returns 202 Accepted; the email is queued for delivery.

Request body:

{
  "from_": {
    "email": "[email protected]",
    "name": "Your Company"
  },
  "to": [
    { "email": "[email protected]", "name": "Jane Doe" }
  ],
  "subject": "Welcome aboard",
  "html": "<h1>Welcome!</h1><p>Thanks for signing up.</p>",
  "text": "Welcome! Thanks for signing up.",
  "cc": [{ "email": "[email protected]" }],
  "bcc": [{ "email": "[email protected]" }],
  "reply_to": { "email": "[email protected]" },
  "headers": { "X-Custom-Header": "value" },
  "tags": ["onboarding"],
  "send_at": "2026-06-01T09:00:00Z"
}
FieldTypeRequiredDescription
from_objectYesSender address object with email and optional name.
from_.emailstringYesSender email address. Must be a registered sender on a verified domain.
from_.namestringNoSender display name.
toarrayYesArray of recipient objects. At least one required.
to[].emailstringYesRecipient email address.
to[].namestringNoRecipient display name.
subjectstringYesEmail subject line.
htmlstringNoHTML body. At least one of html or text is required.
textstringNoPlain-text body.
ccarrayNoArray of CC recipient objects.
bccarrayNoArray of BCC recipient objects.
reply_toobjectNoReply-to address object with email and optional name.
headersobjectNoCustom email headers as a string-to-string map.
tagsstring[]NoTags for filtering in logs and analytics.
send_atstring (ISO 8601)NoSchedule for future delivery. Must be 1 minute to 30 days in the future. Starter plan and above only.
attachmentsarrayNoFile attachments. See below.

Attachment fields:

{
  "attachments": [
    {
      "filename": "invoice.pdf",
      "content_base64": "JVBERi0xLjQ...",
      "content_type": "application/pdf"
    }
  ]
}
FieldTypeRequiredDescription
filenamestringYesFile name. Must not contain path separators.
content_base64stringYesFile body as base64 (no data: prefix).
content_typestringNoMIME type. Defaults to application/octet-stream.

Per-file and combined attachment size are both capped at 24 MiB.

Response (202 Accepted):

{
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "status": "queued",
  "message_id": "<[email protected]>",
  "rejection_reason": null
}
curl -X POST https://mail.axene.io/v1/emails/ \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from_": {"email": "[email protected]", "name": "Your Company"},
    "to": [{"email": "[email protected]"}],
    "subject": "Welcome aboard",
    "html": "<h1>Welcome!</h1>"
  }'

If to, cc, or bcc includes a suppressed address, the send is rejected in this same response ("status": "rejected", rejection_reason explains why) instead of being silently dropped. A deliberate retry within 24 hours -- via retry or by sending again -- delivers once as an override, then the address is re-suppressed. See Suppression Lists for the full behavior.


Send batch emails

POST /v1/emails/batch

Send multiple emails in a single request. Requires the Starter plan or above. The request body is a JSON array of email objects, each using the same shape as the single send body.

PlanMax emails per batch
FreeNot available
Starter25
Pro50
Business100

Batch sending requires the Starter plan or above. Free plan accounts receive a 403 error.

Response (202 Accepted):

{
  "total": 2,
  "sent": 2,
  "failed": 0,
  "results": [
    { "id": "a1b2c3d4-...", "status": "queued", "rejection_reason": null },
    { "id": "b2c3d4e5-...", "status": "queued", "rejection_reason": null }
  ]
}

Each email is processed independently. A failed email has "id": null, "status": "error", and a rejection_reason.


List emails

GET /v1/emails/

Returns an array of emails, newest first.

Query parameters:

ParameterTypeDefaultDescription
statusstring--Filter by status.
pageinteger0Zero-based page number.
limitinteger20Results per page (1-100).
curl "https://mail.axene.io/v1/emails/?status=delivered&limit=10" \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response:

[
  {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "from_address": "Your Company <[email protected]>",
    "to_addresses": ["[email protected]"],
    "subject": "Welcome aboard",
    "status": "delivered",
    "source": "api",
    "opened_count": 1,
    "clicked_count": 0,
    "tags": ["onboarding"],
    "scheduled_at": null,
    "created_at": "2026-04-06T10:00:00Z",
    "sent_at": "2026-04-06T10:00:01Z",
    "delivered_at": "2026-04-06T10:00:03Z",
    "retry_of_id": null
  }
]

Get email updates

GET /v1/emails/updates

Returns up to 50 emails created or updated after a given timestamp. Useful for polling live status changes.

Query parameters:

ParameterTypeRequiredDescription
sincestring (ISO 8601)YesReturn emails updated after this timestamp.
curl "https://mail.axene.io/v1/emails/updates?since=2026-04-06T10:00:00Z" \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response shape matches List emails.


Search emails

GET /v1/emails/search

Search emails by recipient, sender, subject, status, or tags.

Query parameters:

ParameterTypeDefaultDescription
qstring""Free-text query. Supports inline tokens (see below).
statusstring--Filter by status.
tagstring--Filter by an exact tag.
pageinteger0Zero-based page number.
limitinteger20Results per page (1-100).

The q parameter accepts inline tokens that map to structured filters: to:gmail.com, from:[email protected], status:bounced, domain:axene.io, tag:welcome. Any remaining words are matched as free text across sender, subject, and recipients.

curl "https://mail.axene.io/v1/emails/search?q=welcome+status:delivered" \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response: an array of email objects with id, from_address, to_addresses, subject, status, tags, source, created_at, and delivered_at.


List scheduled emails

GET /v1/emails/scheduled

Returns all emails scheduled for future delivery that have not yet been sent.

curl https://mail.axene.io/v1/emails/scheduled \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response:

[
  {
    "id": "b2c3d4e5-6789-01bc-defg-2345678901bc",
    "from_address": "Your Company <[email protected]>",
    "to_addresses": ["[email protected]"],
    "subject": "Reminder",
    "status": "scheduled",
    "tags": null,
    "scheduled_at": "2026-06-01T09:00:00Z",
    "seconds_until_send": 432000,
    "created_at": "2026-04-06T10:00:00Z"
  }
]

Cancel a scheduled email

DELETE /v1/emails/scheduled/{email_id}

Cancels a scheduled email before it sends. Returns 404 if the email is not scheduled.

curl -X DELETE https://mail.axene.io/v1/emails/scheduled/b2c3d4e5-... \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response (200 OK):

{ "id": "b2c3d4e5-...", "status": "cancelled" }

Send a scheduled email now

POST /v1/emails/scheduled/{email_id}/send-now

Dispatches a scheduled email immediately instead of waiting for scheduled_at.

curl -X POST https://mail.axene.io/v1/emails/scheduled/b2c3d4e5-.../send-now \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response (200 OK):

{ "id": "b2c3d4e5-...", "status": "queued" }

Suppression state is re-checked at this point too (it may have changed since the email was scheduled). If the recipient is now suppressed and not eligible for a retry override, this returns 422 Unprocessable Entity with the reason instead, and the email's status becomes rejected.


Validate an email (dry run)

POST /v1/emails/validate

Checks whether an email would send without actually sending it. Validates the sender address, domain verification, plan limits, and account restrictions. The request body uses the same shape as Send an email.

curl -X POST https://mail.axene.io/v1/emails/validate \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from_": {"email": "[email protected]"},
    "to": [{"email": "[email protected]"}],
    "subject": "Test",
    "html": "<p>Test</p>"
  }'

Response (200 OK):

{
  "valid": true,
  "can_send": true,
  "issues": [],
  "plan": "starter",
  "usage": {
    "daily": 12,
    "daily_limit": 200,
    "monthly": 340,
    "monthly_limit": 5000
  }
}

When validation fails, valid and can_send are false and issues lists the problems. Each issue is { "field": "...", "error": "..." }. The field is one of account, from, limits, to, or content. A to issue is raised for a suppressed recipient that would currently be rejected; a suppressed recipient whose retry override is currently available (see Sending to a suppressed recipient) is not flagged, since that send would go through. Validating never consumes the override itself.

Use the validate endpoint in your CI/CD pipeline to catch sender or configuration errors before they reach production.


Get email detail

GET /v1/emails/{email_id}

Returns full details for a single email, including the body, headers, and event timeline.

curl https://mail.axene.io/v1/emails/a1b2c3d4-... \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response:

{
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "from_address": "Your Company <[email protected]>",
  "to_addresses": ["[email protected]"],
  "subject": "Welcome aboard",
  "status": "delivered",
  "source": "api",
  "opened_count": 1,
  "clicked_count": 0,
  "tags": ["onboarding"],
  "scheduled_at": null,
  "created_at": "2026-04-06T10:00:00Z",
  "sent_at": "2026-04-06T10:00:01Z",
  "delivered_at": "2026-04-06T10:00:03Z",
  "retry_of_id": null,
  "cc_addresses": null,
  "bcc_addresses": null,
  "text_body": "Welcome! Thanks for signing up.",
  "html_body": "<h1>Welcome!</h1>",
  "headers": {},
  "message_id": "<[email protected]>",
  "events": []
}

Retry an email

POST /v1/emails/{email_id}/retry

Resends a previously failed email. Only emails with status bounced, rejected, or failed can be retried; any other status returns 409 Conflict. A new email row is created, linked to the original via retry_of_id.

For an email rejected because its recipient was suppressed, retrying within 24 hours of the rejection is exactly how you use the one-time override described in Sending to a suppressed recipient -- the retry goes through once, then the address is suppressed again.

curl -X POST https://mail.axene.io/v1/emails/a1b2c3d4-.../retry \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response (202 Accepted):

{
  "id": "c3d4e5f6-...",
  "status": "queued",
  "message_id": "<[email protected]>",
  "rejection_reason": null
}

Get email events

GET /v1/emails/{email_id}/events

Returns the event timeline for a specific email.

curl https://mail.axene.io/v1/emails/a1b2c3d4-.../events \
  -H "Authorization: Bearer axm_k_YOUR_API_KEY"

Response:

[
  {
    "id": "e1f2a3b4-...",
    "event_type": "queued",
    "metadata": null,
    "created_at": "2026-04-06T10:00:00Z"
  },
  {
    "id": "e2f3a4b5-...",
    "event_type": "delivered",
    "metadata": { "relay": "mx.example.com", "dsn": "2.0.0" },
    "created_at": "2026-04-06T10:00:03Z"
  }
]

Saved searches

Named filter sets for the email log, stored per user.

List saved searches

GET /v1/emails/saved-searches

Returns { "searches": [...] }.

Replace saved searches

PUT /v1/emails/saved-searches

Replaces the entire saved-search list. Body: { "searches": [...] }, capped at 50 entries. Each entry supports id, name, query, range, status, domain, and source fields.

On this page