Home / API
API Reference

MailLogic API Docs

MailLogic API reference: authentication, scopes, domains, email accounts, usage, email logs, forwarding tests, Send and Batch Send.

https://api.maillogic.io

Overview

The public API has 13 operations and two separate authentication models.

  • Personal Access Tokens (PATs / automation tokens) authorize management operations: domains, email accounts, usage, email logs, DNS checks and forwarding tests. Each token has explicit scopes and optional domain restrictions.
  • Domain API keys authorize Send and Batch Send for a sending domain. PATs cannot be used for Send/Batch Send; domain API keys cannot be used for management operations.

Base URL and authentication

Base URL: https://api.maillogic.io. Use HTTPS and keep secrets on your server, outside browser code and source control.

For management requests, use Authorization: Bearer $MAILLOGIC_TOKEN with an mlpat_ token. In the dashboard, open Automation tokens, choose permissions and all owned domains or selected domains, then create a token. Copy the secret immediately: it is shown only once. Dashboard tokens expire after 90 days. Expired or revoked tokens return 401; revocation immediately disables subsequent authentication.

Scopes are independent: DNS checks and test creation do not grant read permissions. Domain-restricted tokens see only permitted owned domains; inaccessible resources return 404. usage:read requires an unrestricted token because usage is account-wide.

Sending uses an mlk_ domain API key: Authorization: Bearer $MAILLOGIC_DOMAIN_KEY, or alternatively X-API-Key: $MAILLOGIC_DOMAIN_KEY. These credentials are not interchangeable with PATs.

Operation reference

OperationAuthentication / required scope
GET /v1/domainsPAT · domains:read
GET /v1/domains/{id}PAT · domains:read
POST /v1/domains/{id}/check-dnsPAT · domains:check-dns
GET /v1/email-accountsPAT · email-accounts:read
GET /v1/email-accounts/{id}PAT · email-accounts:read
GET /v1/usagePAT · usage:read
GET /v1/logsPAT · logs:read
POST /v1/forwarding-testsPAT · forwarding-tests:create
GET /v1/forwarding-tests/{id}PAT · forwarding-tests:read
POST /v1/sendDomain API key
POST /v1/batch-send/previewDomain API key
POST /v1/batch-sendDomain API key
GET /v1/batch-send/{batch_id}Domain API key

Quick start

These examples use a POSIX shell and curl. Create an unrestricted PAT with domains:read, email-accounts:read and usage:read. Replace the placeholder token and IDs with your own values.

quick-start.sh
export MAILLOGIC_TOKEN='YOUR_AUTOMATION_TOKEN'
export BASE_URL='https://api.maillogic.io'

curl "$BASE_URL/v1/domains" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN"

export DOMAIN_ID='UUID_FROM_DOMAINS_DATA'
curl "$BASE_URL/v1/domains/$DOMAIN_ID" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN"

curl --get "$BASE_URL/v1/email-accounts" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN" \
  --data-urlencode "domain_id=$DOMAIN_ID"

curl "$BASE_URL/v1/usage" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN"

Domain and email-account lists return {"data": [...], "next_cursor": null}; detail requests return the object directly. IDs are UUIDs. Lists accept limit (1–200, default 50) and cursor. Pass next_cursor unchanged as the next cursor using the same token and filters; null ends pagination. Encode query values with curl --data-urlencode. Logs use the same page envelope.

Domains

GET /v1/domains supports name (exact, case-insensitive, optional final dot) and ownership_status (pending, verified, revoked). GET /v1/domains/{id} returns one domain.

Fields: id, name, ownership_status, forwarding_ready, smtp_ready, dns, last_checked_at, created_at, updated_at. Reads return cached observations, not live checks or delivery guarantees.

  • forwarding_ready requires a prior check, verified ownership and both expected MX records. It does not depend on outbound SPF/DKIM/DMARC readiness.
  • For Basic/non-SMTP-entitled accounts, "smtp_ready": null means not applicable. Outbound dns.spf, dns.dkim, dns.dkim_smtp1, dns.dkim_smtp2 and dns.dmarc are also null.
  • SMTP-entitled accounts receive boolean smtp_ready: false means sending readiness is not satisfied; true means cached domain readiness and account sending policy permit it. Individual sender checks still apply. After a DNS check, outbound observations are booleans; cached DNS fields can be null before any check.
  • dns.mx_10 and dns.mx_20 apply to forwarding on all plans. A checked DNS value of false means the check applies but is not satisfied; true means it is satisfied.

Refresh DNS and ownership

POST /v1/domains/{id}/check-dns requires domains:check-dns; no body or Idempotency-Key is required. This action may update stored DNS/ownership state and trigger mail-configuration reconciliation.

check-dns.sh
curl --request POST "$BASE_URL/v1/domains/$DOMAIN_ID/check-dns" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN"

The response has checks, ownership (verified, state), checked_at and the refreshed domain. Live checks contains mx_10, mx_20, mx, unexpected_mx, spf, dkim, dkim_smtp1, dkim_smtp2, dmarc. Outbound checks remain null without SMTP entitlement.

404 hides inaccessible domains; 409 can mean another account holds verified ownership; 429 means throttling or a concurrent check (honor Retry-After); 503 means DNS, storage or downstream state could not be resolved. A 503 may follow a saved update: inspect detail.params.state_persisted when present and retry the same action.

Email accounts

GET /v1/email-accounts accepts optional domain_id and active filters. GET /v1/email-accounts/{id} returns one account. Both require email-accounts:read, which exposes the forwarding destination.

Fields: id, domain_id, address, nullable display_name and forward_to, active, smtp_enabled, forwarding_test_eligibility, created_at, updated_at. smtp_enabled is configuration, not a guarantee that sending is possible.

domain_id identifies the parent domain. Pass the email account’s id as email_account_id when creating a forwarding test; it uses the configured alias and destination. Eligibility includes eligible and nullable reason: ownership_mismatch, username_inactive, forwarding_destination_missing, domain_ownership_unverified or inbound_mx_unverified. Creation rechecks eligibility.

Usage

GET /v1/usage requires usage:read and unrestricted domain access. It returns measured_at, plan, plan_name, email_accounts, smtp and smtp_sending_state.

email_accounts.used counts all accounts, including inactive ones; email_accounts.limit is the plan limit. smtp is null without SMTP entitlement. Otherwise it contains unit (recipients), period_start, nullable period_end, rolling_period, included_limit, used, included_used, included_available, purchased_available, reserved and usable_available. Usable capacity includes included and purchased credits after active reservations.

smtp_sending_state: not_entitled, suspended, billing_operation_in_progress, credits_exhausted or available. This describes account policy and capacity; sender/domain eligibility and admission limits still apply. A failed usage dependency returns an error, not fabricated zero usage.

Email logs

GET /v1/logs?domain_id=$DOMAIN_ID requires logs:read, access to that domain, current verified ownership and a plan that includes logs. Missing plan access returns 403; unverified ownership can return 409. Only activity attributable to current ownership is exposed.

Alongside pagination, filters are since (inclusive), until (exclusive), search, activity_type (forwarding or outbound) and status. Times must be RFC3339 with UTC/offset. The query window is at most 30 days; by default it ends at the first-page request time and starts 30 days earlier. This is a query-window limit, not a retention guarantee. Search is a case-insensitive literal address/identity substring, not message-content search.

Each item has id, occurred_at, activity_type, nullable sender, recipient, recipient_count, status, and nullable reason with smtp_code and enhanced_status. occurred_at is forwarding occurrence or outbound recipient submission time, not the latest delivery time. No message bodies are returned.

Statuses: submitted, accepted, deferred, bounced, failed, suppressed, unknown, forwarded, blocked. submitted means local submission; forwarded means forwarding handoff; accepted means trusted recipient SMTP acceptance, not inbox placement.

Forwarding tests

POST /v1/forwarding-tests requires forwarding-tests:create, exactly one Idempotency-Key header and a JSON email_account_id UUID. Optional locale is en (default) or ja. Keys are case-sensitive, 1–128 printable ASCII characters without whitespace. The diagnostic sends a server-controlled email through the selected alias to its configured forwarding destination.

forwarding-test.sh
export EMAIL_ACCOUNT_ID='UUID_FROM_EMAIL_ACCOUNTS_DATA'
export IDEMPOTENCY_KEY='forwarding-check-001'
curl --include --request POST "$BASE_URL/v1/forwarding-tests" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --header 'Content-Type: application/json' \
  --data "{\"email_account_id\":\"$EMAIL_ACCOUNT_ID\",\"locale\":\"en\"}"

export TEST_ID='UUID_FROM_TEST_RESPONSE'
curl "$BASE_URL/v1/forwarding-tests/$TEST_ID" \
  --header "Authorization: Bearer $MAILLOGIC_TOKEN"

Durable acceptance returns 202, even during a temporary queue outage. Location points to /v1/forwarding-tests/{id}. Repeating the same key and request in the same account returns the same test without another send, with Idempotency-Replayed: true. Replay is supported for at least 30 days; see replay_expires_at. A changed request with the same key returns 409. A different test for the same alias can hit the five-minute cooldown (429 with Retry-After).

GET /v1/forwarding-tests/{id} requires forwarding-tests:read. It reads and reconciles results; it never sends another email. Poll active results according to poll_after_ms. Active statuses are queued, submitting, checking; terminal statuses are confirmed and failed. confirmed means MailLogic observed destination SMTP acceptance, not inbox placement. A timeout or uncertain result does not prove non-delivery.

Both operations return id, nullable email_account_id and domain_id, alias, destination, locale, status, nullable failure_code, created_at, nullable submitted_at, confirmed_at and failed_at, monitoring_deadline_at, replay_expires_at and nullable poll_after_ms. Domain-restricted tokens cannot read historical tests after their domain is deleted.

Send and Batch Send

Use domain API keys, not PATs. Generate a key in the selected domain’s API section. Sending requires an eligible plan, an active sender on the key’s domain with SMTP enabled and a password set, and verified ownership/sending DNS.

  • POST /v1/send: form data with from_email, repeated to_email, subject, optional text_content, html_content, display_name and attachments. Optional Idempotency-Key. A 200 response includes status, message, message_id, from_email, to_email, recipient arrays (accepted_recipients, rejected_recipients, suppressed_recipients) and their counts.
  • POST /v1/batch-send/preview: validate a JSON draft and return previews, recipient counts, headers, referenced variables, warnings and quota; does not send.
  • POST /v1/batch-send: submit the JSON draft with required Idempotency-Key. Returns 202 with batch, duplicate, quota and a Location header.
  • GET /v1/batch-send/{batch_id}: return the batch object and progress/outcome counts.

Batch drafts contain from_email, subject_template, text_template/html_template and recipients with email and variables. See the Send API and Batch Send guide for full examples, limits, idempotency and response details. Submission success does not guarantee final delivery.

Errors and rate limits

Management errors use this envelope. detail.request_id matches the X-Request-ID response header; include it when reporting an issue. Successful management responses also carry that header. Sending endpoints retain their separate error contract; see the sending guide.

Example management error
{
  "detail": {
    "code": "auth.insufficient_scope",
    "message": "The token does not grant this operation.",
    "params": {"required_scope": "domains:read"},
    "request_id": "00000000-0000-4000-8000-000000000001"
  }
}
  • 401: missing, invalid, expired or revoked PAT (WWW-Authenticate: Bearer).
  • 403: missing scope, restricted token used for account-wide usage, or missing plan/access entitlement.
  • 404: missing resource, another account’s resource or a domain outside the token’s restriction.
  • 409: ownership/eligibility conflict or an Idempotency-Key reused with changed input.
  • 422: invalid parameters, UUID, cursor, date range, body or idempotency header.
  • 429: rate limit, concurrent action or forwarding-test cooldown. Wait the Retry-After seconds before retrying.
  • 503: temporarily unavailable dependency or operation. Honor Retry-After when provided. For uncertain forwarding-test creation, retry with the same key and request.

Management authentication currently limits peer requests to 120/minute, token credential requests to 60/minute, and authenticated account requests to 300/minute. Action-specific limits also apply. Honor returned retry guidance rather than polling aggressively. Ordinary Send API traffic has a separate account-wide limit of one new SMTP submission per second and returns 429 with Retry-After when exceeded.

OpenAPI

The public OpenAPI schema is the machine-readable contract for these 13 operations, including request/response schemas and authentication requirements. It is publicly readable without a token.