Receiving domains
A custom domain lets your agent send and receive mail on a hostname you control —
mail.acmerobotics.com instead of the shared platform domain (agentmail.ackuna.com). It is a
self-serve, paid-plan feature: registering one provisions a linked sending identity for that
hostname and returns the DNS records you need to publish. Once they verify, Ackuna activates
the domain by itself — no manual review — and it can host inboxes.
Why register one. Sending from the shared domain agentmail.ackuna.com (and from
existing inboxes on the earlier shared domain agents.ackuna.com) is
limited to 100 messages a day per account, both domains together. Mail from inboxes on your own
domain is not subject to that limit; your plan's limits, the limits for new
workspaces and the workspace's hourly send limit still apply. The domain needs an
MX record pointing at our inbound server, and its DKIM records. If your main domain
already receives mail elsewhere (Google Workspace, Microsoft 365), register a
subdomain such as mail.example.com.
The receiving domain object
{
"id": "dom_01k2n9v8qf3m7d5b0y6xz4rt3e",
"object": "receiving_domain",
"domain": "mail.acmerobotics.com",
"status": "active",
"mx_status": "ok",
"dkim_status": "ok",
"required_records": [
{"type": "MX", "name": "mail.acmerobotics.com", "value": "inbound-smtp.us-east-1.amazonaws.com", "priority": 10},
{"type": "CNAME", "host": "sj4f9k2m1q7r._domainkey", "value": "sj4f9k2m1q7r.dkim.amazonses.com", "status": "verified"},
{"type": "CNAME", "host": "b8n3x6w0p5t2._domainkey", "value": "b8n3x6w0p5t2.dkim.amazonses.com", "status": "verified"},
{"type": "CNAME", "host": "h1c7y4v9e2u6._domainkey", "value": "h1c7y4v9e2u6.dkim.amazonses.com", "status": "verified"}
],
"verified_at": "2026-08-20T09:12:00.000Z",
"activated_at": "2026-08-20T09:14:00.000Z",
"created_at": "2026-08-20T09:00:00.000Z"
}
status moves through pending (just registered, no DNS confirmed yet) → verifying (MX
has been seen; DKIM and the sending identity are still being confirmed) → active (fully
verified and usable in POST /v1/inboxes) automatically — there is no manual activation
step. A domain that never reaches active within 14 days of registration is marked stale:
it stops being probed, and its hostname is freed for your own organization to register
again (a different organization registering the same hostname still gets domain_taken).
mx_status reflects the outcome of the most recent automated MX probe (missing, ok, or
mismatched). dkim_status reflects the automated check of this domain's linked sending
identity's DKIM CNAMEs: pending until every CNAME verifies, then ok. required_records
is always the current, complete list of DNS records to publish — one MX record (enables
receiving) plus the sending identity's DKIM CNAME records (enable sending, and prove control
of the domain). The domain becomes able to send once its linked sending identity finishes
verifying, so publish the DKIM records promptly if you plan to send as well as receive.
There is no webhook event for activation; poll GET /v1/domains/{domain} and watch
status.
List receiving domains
GET /v1/domains?limit=25
Authorization: Bearer ak_...
Requires scope domains:read.
Register a receiving domain
POST /v1/domains
Authorization: Bearer ak_...
Content-Type: application/json
Idempotency-Key: register-mail-domain-1
{"domain": "mail.acmerobotics.com"}
{
"data": {
"id": "dom_01k2n9v8qf3m7d5b0y6xz4rt3e",
"object": "receiving_domain",
"domain": "mail.acmerobotics.com",
"status": "pending",
"mx_status": "missing",
"dkim_status": "pending",
"required_records": [
{"type": "MX", "name": "mail.acmerobotics.com", "value": "inbound-smtp.us-east-1.amazonaws.com", "priority": 10}
],
"verified_at": null,
"activated_at": null,
"created_at": "2026-08-20T09:00:00.000Z"
}
}
Requires scope domains:write and a paid plan with custom-domain capacity remaining (the
free tier has none). domain is required — a hostname, lowercased before use, up to 253
characters. Registering provisions a linked sending identity for the hostname in the
background, so the three DKIM CNAME records are added to required_records within moments
of this response, not necessarily inside it — poll GET /v1/domains/{domain} to pick them
up. Publish every record required_records ends up listing at your DNS provider, then keep
polling GET /v1/domains/{domain} until status is active. Once active, pass this
domain's id as domain on POST /v1/inboxes to host an inbox there.
403 quota_exceeded if the organization has no custom-domain capacity left on its plan
(including the free tier, which has none). 422 invalid_request if the hostname fails
validation or names the platform's own shared domain (which cannot be registered by any
organization); 422 domain_taken if the hostname is already registered.
Fetch a receiving domain
GET /v1/domains/dom_01k2n9v8qf3m7d5b0y6xz4rt3e
Authorization: Bearer ak_...
Requires scope domains:read. Returns the current object — the fastest way to check what
requirement is still outstanding while onboarding a domain. 404 not_found for an unknown
or cross-organization id.
Delete a receiving domain
DELETE /v1/domains/dom_01k2n9v8qf3m7d5b0y6xz4rt3e
Authorization: Bearer ak_...
Idempotency-Key: delete-mail-domain-1
Requires scope domains:write. Returns {"data": null}. 409 invalid_request if the
domain still hosts one or more inboxes — move or delete them first. 404 not_found for an
unknown or cross-organization id.
See Errors for the full error-code reference, or Versioning for how this contract changes over time.