Skip to content
machinemail

Domains

Custom domains, DNS records, catch-all.

MethodPathSummary
GET/v0/domainsList Domains
POST/v0/domainsCreate Domain
GET/v0/domains/{domain_id}Get Domain
PATCH/v0/domains/{domain_id}Update Domain
DELETE/v0/domains/{domain_id}Delete Domain
GET/v0/domains/{domain_id}/domain-connectGet Domain Connect Setup
POST/v0/domains/{domain_id}/verifyVerify Domain
GET/v0/domains/{domain_id}/zone-fileGet Zone File
GET/v0/pods/{pod_id}/domainsList Domains in Pod
POST/v0/pods/{pod_id}/domainsCreate Domain in Pod
GET/v0/pods/{pod_id}/domains/{domain_id}Get Domain in Pod
PATCH/v0/pods/{pod_id}/domains/{domain_id}Update Domain in Pod
DELETE/v0/pods/{pod_id}/domains/{domain_id}Delete Domain in Pod
GET/v0/pods/{pod_id}/domains/{domain_id}/domain-connectGet Domain Connect Setup in Pod
POST/v0/pods/{pod_id}/domains/{domain_id}/verifyVerify Domain in Pod
GET/v0/pods/{pod_id}/domains/{domain_id}/zone-fileGet Zone File in Pod

List Domains

http
GET /v0/domains

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Query parameters

limitinteger
Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_tokenstring
next_page_token from the previous page.
ascendingboolean
Sort oldest first.

Response

200 A page of domains (application/json)

countintegerRequired
Number of items returned.
limitinteger
Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_tokenstring
Page token for pagination. Absent on the last page.
domainsDomainItem[]Required
Ordered by created_at, newest first unless ascending is set.

Each item of domains is a DomainItem:

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
Verification status, as on Domain.
reasonstring
Why the domain is not verified yet, as on Domain.
recordsVerificationRecord[]Required
DNS records to publish, as on Domain.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/domains" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "domains": [
    {
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
      "domain": "example.com",
      "feedback_enabled": false,
      "inbound_enabled": false,
      "subdomains_enabled": false,
      "tracking_enabled": false,
      "client_id": "my-client-id",
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "status": "NOT_STARTED",
      "reason": "string",
      "records": [
        {
          "type": "TXT",
          "name": "Production",
          "value": "string",
          "status": "MISSING",
          "priority": 1,
          "reason": "string",
          "purpose": "inbound",
          "required": false
        }
      ],
      "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
      "catch_all": false,
      "catch_all_ttl_seconds": 1,
      "nameservers": ["string"],
      "dns_provider": "cloudflare",
      "dns_provider_url": "https://example.com",
      "domain_connect": {
        "supported": false,
        "provider_name": "string",
        "apply_url": "https://example.com"
      },
      "verified_at": "2026-10-01T12:00:00.000Z",
      "last_checked_at": "2026-10-01T12:00:00.000Z"
    }
  ]
}

Create Domain

http
POST /v0/domains

Registers the domain and returns the DNS records to publish (status: NOT_STARTED). Publish them, then call Verify Domain. A background worker re-checks PENDING and INVALID domains about every 5 minutes until 7 days after creation; a NOT_STARTED domain is only checked by Verify Domain.

A domain can be registered by one organization only (409), and the shared domain cannot be added (409). Inbox-scoped credentials cannot add domains (403).

allow_conflicting_provider, subdomains_enabled and tracking_enabled are not supported.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_create.

Request body

Content type: application/json.

domainstringRequired
The domain name, for example example.com. Cannot be the shared domain or a domain another organization registered.
feedback_enabledboolean
Stored and returned; has no effect. Default false.
inbound_enabledboolean
Receive email for this domain. Default true. false makes it send-only (the inbound MX record is not required).
client_idstring
Idempotency key: a create with a client_id already used in the organization returns that domain with 200.
pod_idstring
Pod to create the domain in. Defaults to the credential pod or the organization default pod. A pod-scoped credential can only name its own pod.
catch_allboolean
Create an inbox for any address at the domain that receives mail. Default false.
catch_all_ttl_secondsinteger | null
Make inboxes created by catch-all ephemeral with this TTL. null or absent: permanent.

Response

200 A domain with this client_id already exists; it is returned unchanged. (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

201 Created (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
409Conflicts with an existing resource.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/domains" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "domain": "example.com",
  "feedback_enabled": false
}'
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Get Domain

http
GET /v0/domains/{domain_id}

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

domain_idstringRequired
ID of the domain.

Response

200 The domain (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Update Domain

http
PATCH /v0/domains/{domain_id}

Fields you omit are unchanged. subdomains_enabled and tracking_enabled are not supported.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_update.

Path parameters

domain_idstringRequired
ID of the domain.

Request body

Content type: application/json.

feedback_enabledboolean
Stored and returned; has no effect.
inbound_enabledboolean
Receive email for this domain. false makes the inbound MX record optional and re-evaluates the status.
catch_allboolean
Create an inbox for any address at the domain that receives mail.
catch_all_ttl_secondsinteger | null
TTL of inboxes created by catch-all from now on. null makes them permanent.

Response

200 The updated domain (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X PATCH "https://api.machinemail.dev/v0/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "feedback_enabled": false
}'
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Delete Domain

http
DELETE /v0/domains/{domain_id}

Inboxes on the domain are not deleted.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_delete.

Path parameters

domain_idstringRequired
ID of the domain.

Response

200 Deleted (application/json)

oktrueRequired

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X DELETE "https://api.machinemail.dev/v0/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "ok": true
}

Get Domain Connect Setup

http
GET /v0/domains/{domain_id}/domain-connect

Discovers whether the domain’s DNS provider supports Domain Connect (TXT _domainconnect.<zone> and the provider’s /v2/<zone>/settings) and has onboarded the MachineMail template (machinemail.dev/email). When it has, apply_url is a signed synchronous-flow link (RS256, key=_dck1, sig last) that opens the provider with the outstanding MX, SPF, DKIM and DMARC records prefilled. Discovery is cached on the domain (6 h; provider errors 10 min) and re-run by Verify Domain.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

domain_idstringRequired
ID of the domain.

Response

200 Domain Connect support for the domain (application/json)

supportedbooleanRequired
The zone DNS provider supports Domain Connect and has the MachineMail template.
provider_namestring
Display name of the DNS provider.
apply_urlstring
Signed link that opens the provider with the outstanding records prefilled. Absent when nothing is left to add.
provider_idstring
Domain Connect provider ID.
url_sync_uxstring
Base URL of the provider synchronous flow.
widthinteger
Suggested popup width, in pixels.
heightinteger
Suggested popup height, in pixels.
reason"no_domain_connect" | "provider_error" | "no_sync_flow" | "template_not_supported" | "records_not_templatable" | "already_configured" | "not_configured"
Why one-click setup is not available, or already_configured when nothing is left to add.
checked_atstring (date-time)Required
When discovery last ran.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m/domain-connect" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "supported": false,
  "provider_name": "string",
  "apply_url": "https://example.com",
  "provider_id": "string",
  "url_sync_ux": "string",
  "width": 1,
  "height": 1,
  "reason": "no_domain_connect",
  "checked_at": "2026-10-01T12:00:00.000Z"
}

Verify Domain

http
POST /v0/domains/{domain_id}/verify

Checks every DNS record now, updates records[].status and status, and re-runs Domain Connect discovery. A domain.verified event is emitted when the domain becomes VERIFIED.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_update.

Path parameters

domain_idstringRequired
ID of the domain.

Response

200 The domain after the check (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m/verify" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Get Zone File

http
GET /v0/domains/{domain_id}/zone-file

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

domain_idstringRequired
ID of the domain.

Response

200 A BIND zone file with the records to publish (text/plain)

Headers:

Content-Dispositionstring
attachment; filename="<domain>.zone"

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m/zone-file" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

List Domains in Pod

http
GET /v0/pods/{pod_id}/domains

Same as List Domains (GET /v0/domains), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

pod_idstringRequired
ID of the pod.

Query parameters

limitinteger
Maximum number of items to return. Default 50, maximum 500; larger values are capped.
page_tokenstring
next_page_token from the previous page.
ascendingboolean
Sort oldest first.

Response

200 A page of domains (application/json)

countintegerRequired
Number of items returned.
limitinteger
Maximum number of items per page. Default 50, maximum 500; larger values are capped.
next_page_tokenstring
Page token for pagination. Absent on the last page.
domainsDomainItem[]Required
Ordered by created_at, newest first unless ascending is set.

Each item of domains is a DomainItem:

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
Verification status, as on Domain.
reasonstring
Why the domain is not verified yet, as on Domain.
recordsVerificationRecord[]Required
DNS records to publish, as on Domain.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "domains": [
    {
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
      "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
      "domain": "example.com",
      "feedback_enabled": false,
      "inbound_enabled": false,
      "subdomains_enabled": false,
      "tracking_enabled": false,
      "client_id": "my-client-id",
      "updated_at": "2026-10-01T12:00:00.000Z",
      "created_at": "2026-10-01T12:00:00.000Z",
      "status": "NOT_STARTED",
      "reason": "string",
      "records": [
        {
          "type": "TXT",
          "name": "Production",
          "value": "string",
          "status": "MISSING",
          "priority": 1,
          "reason": "string",
          "purpose": "inbound",
          "required": false
        }
      ],
      "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
      "catch_all": false,
      "catch_all_ttl_seconds": 1,
      "nameservers": ["string"],
      "dns_provider": "cloudflare",
      "dns_provider_url": "https://example.com",
      "domain_connect": {
        "supported": false,
        "provider_name": "string",
        "apply_url": "https://example.com"
      },
      "verified_at": "2026-10-01T12:00:00.000Z",
      "last_checked_at": "2026-10-01T12:00:00.000Z"
    }
  ]
}

Create Domain in Pod

http
POST /v0/pods/{pod_id}/domains

Same as Create Domain (POST /v0/domains), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_create.

Path parameters

pod_idstringRequired
ID of the pod.

Request body

Content type: application/json.

domainstringRequired
The domain name, for example example.com. Cannot be the shared domain or a domain another organization registered.
feedback_enabledboolean
Stored and returned; has no effect. Default false.
inbound_enabledboolean
Receive email for this domain. Default true. false makes it send-only (the inbound MX record is not required).
client_idstring
Idempotency key: a create with a client_id already used in the organization returns that domain with 200.
pod_idstring
Pod to create the domain in. Defaults to the credential pod or the organization default pod. A pod-scoped credential can only name its own pod.
catch_allboolean
Create an inbox for any address at the domain that receives mail. Default false.
catch_all_ttl_secondsinteger | null
Make inboxes created by catch-all ephemeral with this TTL. null or absent: permanent.

Response

200 A domain with this client_id already exists; it is returned unchanged. (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

201 Created (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
409Conflicts with an existing resource.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "domain": "example.com",
  "feedback_enabled": false
}'
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Get Domain in Pod

http
GET /v0/pods/{pod_id}/domains/{domain_id}

Same as Get Domain (GET /v0/domains/{domain_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

pod_idstringRequired
ID of the pod.
domain_idstringRequired
ID of the domain.

Response

200 The domain (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Update Domain in Pod

http
PATCH /v0/pods/{pod_id}/domains/{domain_id}

Same as Update Domain (PATCH /v0/domains/{domain_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_update.

Path parameters

pod_idstringRequired
ID of the pod.
domain_idstringRequired
ID of the domain.

Request body

Content type: application/json.

feedback_enabledboolean
Stored and returned; has no effect.
inbound_enabledboolean
Receive email for this domain. false makes the inbound MX record optional and re-evaluates the status.
catch_allboolean
Create an inbox for any address at the domain that receives mail.
catch_all_ttl_secondsinteger | null
TTL of inboxes created by catch-all from now on. null makes them permanent.

Response

200 The updated domain (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
400Invalid request: error.type is validation and error.param names the field.
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X PATCH "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "feedback_enabled": false
}'
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Delete Domain in Pod

http
DELETE /v0/pods/{pod_id}/domains/{domain_id}

Same as Delete Domain (DELETE /v0/domains/{domain_id}), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_delete.

Path parameters

pod_idstringRequired
ID of the pod.
domain_idstringRequired
ID of the domain.

Response

200 Deleted (application/json)

oktrueRequired

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X DELETE "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "ok": true
}

Get Domain Connect Setup in Pod

http
GET /v0/pods/{pod_id}/domains/{domain_id}/domain-connect

Same as Get Domain Connect Setup (GET /v0/domains/{domain_id}/domain-connect), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

pod_idstringRequired
ID of the pod.
domain_idstringRequired
ID of the domain.

Response

200 Domain Connect support for the domain (application/json)

supportedbooleanRequired
The zone DNS provider supports Domain Connect and has the MachineMail template.
provider_namestring
Display name of the DNS provider.
apply_urlstring
Signed link that opens the provider with the outstanding records prefilled. Absent when nothing is left to add.
provider_idstring
Domain Connect provider ID.
url_sync_uxstring
Base URL of the provider synchronous flow.
widthinteger
Suggested popup width, in pixels.
heightinteger
Suggested popup height, in pixels.
reason"no_domain_connect" | "provider_error" | "no_sync_flow" | "template_not_supported" | "records_not_templatable" | "already_configured" | "not_configured"
Why one-click setup is not available, or already_configured when nothing is left to add.
checked_atstring (date-time)Required
When discovery last ran.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m/domain-connect" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "supported": false,
  "provider_name": "string",
  "apply_url": "https://example.com",
  "provider_id": "string",
  "url_sync_ux": "string",
  "width": 1,
  "height": 1,
  "reason": "no_domain_connect",
  "checked_at": "2026-10-01T12:00:00.000Z"
}

Verify Domain in Pod

http
POST /v0/pods/{pod_id}/domains/{domain_id}/verify

Same as Verify Domain (POST /v0/domains/{domain_id}/verify), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_update.

Path parameters

pod_idstringRequired
ID of the pod.
domain_idstringRequired
ID of the domain.

Response

200 The domain after the check (application/json)

pod_idstringRequired
ID of the pod the domain belongs to.
domain_idstringRequired
ID of the domain.
domainstringRequired
The domain name (for example example.com), lowercased.
feedback_enabledbooleanRequired
Stored as given. MachineMail does not send bounce and complaint notifications to inboxes; use the message.bounced and message.complained events.
inbound_enabledbooleanRequired
Receive email for this domain. false makes it send-only: the inbound MX record is not required.
subdomains_enabledbooleanRequired
Always false: inboxes on subdomains are not supported.
tracking_enabledbooleanRequired
Always false: open tracking is not supported.
client_idstring
Client ID given at creation (idempotency key).
updated_atstring (date-time)Required
Time at which the domain was last updated.
created_atstring (date-time)Required
Time at which the domain was created.
status"NOT_STARTED" | "PENDING" | "INVALID" | "FAILED" | "VERIFYING" | "VERIFIED"Required
NOT_STARTED until the first verify, then VERIFIED when every required record is valid, INVALID when a required record has the wrong value, otherwise PENDING. FAILED and VERIFYING are part of the enum but never set.
reasonstring
Why the domain is not verified yet: what to do next, or which records are missing or invalid. Absent once VERIFIED.
recordsVerificationRecord[]Required
DNS records to publish.
organization_idstringRequired
ID of the organization.
catch_allbooleanRequired
Mail to any address at the domain without an inbox creates one (created_by: catch_all).
catch_all_ttl_secondsinteger
TTL of inboxes created by catch-all; absent means they are permanent.
nameserversstring[]
Authoritative nameservers, detected on create and verify.
dns_provider"cloudflare" | "route53" | "google" | "vercel" | "namecheap" | "godaddy" | "digitalocean" | "hetzner" | "porkbun" | "other"
DNS host the nameservers belong to.
dns_provider_urlstring
Link to the DNS host console.
domain_connectobject
One-click DNS setup (Domain Connect), from the last discovery. See Get Domain Connect Setup.
verified_atstring (date-time)
When the domain became VERIFIED.
last_checked_atstring (date-time)
When the DNS records were last checked.

Each item of records is a VerificationRecord:

type"TXT" | "CNAME" | "MX"Required
namestringRequired
Name (host) of the record.
valuestringRequired
Value of the record.
status"MISSING" | "INVALID" | "VALID"Required
MISSING: not published yet. INVALID: published with the wrong value.
priorityinteger
Priority of an MX record.
reasonstring
Why an INVALID record is invalid: Found: <values seen>.
purpose"inbound" | "spf" | "dkim" | "dmarc" | "provider"Required
What the record is for. provider records come from the sending provider.
requiredbooleanRequired
Whether the record must be valid for the domain to verify. The inbound MX record is not required when inbound_enabled is false.

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl -X POST "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m/verify" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
Response 200
{
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "domain_id": "dom_01k6x3d5kq0000g3q9sx5b8j0m",
  "domain": "example.com",
  "feedback_enabled": false,
  "inbound_enabled": false,
  "subdomains_enabled": false,
  "tracking_enabled": false,
  "client_id": "my-client-id",
  "updated_at": "2026-10-01T12:00:00.000Z",
  "created_at": "2026-10-01T12:00:00.000Z",
  "status": "NOT_STARTED",
  "reason": "string",
  "records": [
    {
      "type": "TXT",
      "name": "Production",
      "value": "string",
      "status": "MISSING",
      "priority": 1,
      "reason": "string",
      "purpose": "inbound",
      "required": false
    }
  ],
  "organization_id": "org_01k6x2m9qd0000a7h3kq9v2c4e",
  "catch_all": false,
  "catch_all_ttl_seconds": 1,
  "nameservers": ["string"],
  "dns_provider": "cloudflare",
  "dns_provider_url": "https://example.com",
  "domain_connect": {
    "supported": false,
    "provider_name": "string",
    "apply_url": "https://example.com"
  },
  "verified_at": "2026-10-01T12:00:00.000Z",
  "last_checked_at": "2026-10-01T12:00:00.000Z"
}

Get Zone File in Pod

http
GET /v0/pods/{pod_id}/domains/{domain_id}/zone-file

Same as Get Zone File (GET /v0/domains/{domain_id}/zone-file), limited to the pod.

Authentication: Authorization: Bearer <api key> or the dashboard mm_session cookie. Permission: domain_read.

Path parameters

pod_idstringRequired
ID of the pod.
domain_idstringRequired
ID of the domain.

Response

200 A BIND zone file with the records to publish (text/plain)

Headers:

Content-Dispositionstring
attachment; filename="<domain>.zone"

Errors

StatusMeaning
401Missing, invalid, expired or revoked credential.
403The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register).
404Not found. Also returned for resources outside the credential scope.
500Unexpected server error.

Error bodies use the error envelope.

Example

Request
curl "https://api.machinemail.dev/v0/pods/pod_01k6x2m9qd0001b8j4mr0w3d5f/domains/dom_01k6x3d5kq0000g3q9sx5b8j0m/zone-file" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"