---
title: "Verify a domain"
method: POST
path: "/v1/email/domains/{domain_id}/verify"
tags: ["domains"]
---

# Verify a domain

`POST /v1/email/domains/{domain_id}/verify`

## Request

- Base URL: `https://us1.platform.bird.com`
- URL: `https://us1.platform.bird.com/v1/email/domains/{domain_id}/verify`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `bird_session`

Runs a fresh DNS check across the domain's records (DKIM, return path,
DMARC, tracking, inbound MX, and any staged changes) and returns the
updated domain. Use it for an immediate result after publishing or
correcting records. [Get a sending domain](/docs/api/reference/get-domain)
only reports the last stored result. Published records are also re-checked
for you automatically in the background.

A `200` with records still `pending` is not a failure: the records were
not found yet, which is normal while DNS propagates (minutes to hours).
Recently verified records are not re-queried, so the call is safe to
repeat while you wait.

## Path parameters

- `domain_id` string, required

## Headers

- `Idempotency-Key` string
- `X-Workspace-Id` string
- `X-Organization-Id` string

## Response `200`

Verification result.

- Domain
  - `id` string, required
  - `workspace_id` string, required
  - `domain` string, required: The sending domain name. Set at creation and immutable.
  - `vendor` 'other' | 'cloudflare' | 'route53' | 'godaddy' | 'namecheap' | 'google' | 'azure' | 'digitalocean' | 'squarespace', required: The DNS provider hosting this domain's nameservers, so you know which provider's dashboard to manage the required DNS records in. Returns `other` when the provider has not been detected or is not recognized.
  - `status` 'pending' | 'verified' | 'failed' | 'temporary_failure' | 'rejected', required: Domain ownership verification, proven by the DKIM record. Readiness to send or track is reported separately per capability under `capabilities.*.status`. - `pending`: the DKIM record has not been published yet. - `verified`: the DKIM record is in place; ownership is confirmed. - `failed`: a DKIM record exists but does not match the expected value (for example a stale record from an earlier setup), or a previously verified record was removed. Correct the record to recover. - `temporary_failure`: DNS resolution failed transiently, such as from a timeout or unreachable nameserver. Verification retries automatically; do not change the DNS records unless they are incorrect. - `rejected`: the domain was refused for policy reasons and cannot be used for sending. Contact support if you believe this is an error.
  - `settings` DomainSettings, required: Per-domain behavior toggles. Changes apply immediately to new sends.
    - `click_tracking` boolean: Rewrite links in HTML email through your tracking domain to record clicks. You can enable this before your tracking domain has verified; it begins working once verification completes. A tracking domain must be configured; enabling it without one returns `409`.
    - `open_tracking` boolean: Insert a tracking pixel in HTML email to record opens. You can enable this before your tracking domain has verified: it begins working once verification completes. A tracking domain must be configured; enabling it without one returns `409`.
  - `next` NextAction[]: What to do next about this domain, given the state it is in. Each entry names one action and says why it is worth taking, so you can act on this response without working out the order yourself. Present on reads that compute it: an empty list means there is nothing to do, and the field is absent entirely on responses that do not report next actions. This answers whether you own the domain, which is what `status` reports. What each capability still needs before it can send or receive is reported separately under `capabilities`, so an empty list here does not on its own mean the domain is ready.
    - `kind` string, required: What you do about this step. - `operation`: call the operation named in `operation`, then read again. - `external`: act somewhere this API does not reach, then read again. - `wait`: nothing is asked of you, so read again later. - `terminal`: nothing you do resolves this, so stop retrying. Tolerate a value you do not recognize: show the `description` and offer no action.
    - `description` string, required: A short, human-readable label for the step, suitable for display.
    - `operation` string: The operationId to call. Present only when `kind` is `operation`. The operation's own schema says how to call it; this says only which one, and what to address it with.
    - `params` object: The parameters that address the operation, by name: `{"sender_id": "…"}` for an operation on `/v1/sms/senders/{sender_id}/requirements`. A parameter the operation takes in its query string is given the same way, so an operation addressed as `?subject_id=` carries `{"subject_id": "…"}`. Every parameter the call needs is here, whether its value came from the thing you were acting on or is fixed for this step, so you can make the call from this object alone. Present only when `kind` is `operation` and the operation names a subject. A request body, when the operation takes one, is described by the operation's own schema and never appears here.
    - `url` string, uri: A URL to open. Present only when `kind` is `external`, and only when the step has one. An external step whose `description` says to go and do something with no URL to open is normal.
  - `dkim` DomainDKIM, required: Active DKIM signing configuration for the domain.
    - `mode` 'txt' | 'delegated', required: How the DKIM public key is published in your DNS. `txt`: you publish the key as a TXT record. `delegated`: you publish a single CNAME and we host and rotate the key.
    - `selector` string, required: DKIM selector used to sign mail from this domain.
    - `key_size` integer, required: RSA key size in bits.
  - `capabilities` DomainCapabilities, required
    - `sending` DomainCapability, required
      - `status` 'pending' | 'verified' | 'warning' | 'failed' | 'temporary_failure' | 'not_configured', required: Capability verification status. - `pending`: verification has not run, or is currently running. - `verified`: all DNS records for this capability resolved with the expected values. - `warning`: a record for this capability verified before and a recent check no longer matches, but it is still within the grace period. Sending is not yet affected; fix it before the grace period ends. - `failed`: DNS records resolved but at least one value is wrong. Update your DNS to recover. - `temporary_failure`: DNS lookup failed transiently. Verification retries automatically; do not change DNS records unless they are incorrect. - `not_configured`: the capability is not set up on this domain (for example, no tracking domain configured).
      - `domain` string, nullable: Hostname this capability is configured with: the return-path domain, the tracking domain, or the domain where the DMARC policy was found. `null` when not applicable or not configured.
      - `pending` DomainCapabilityPending: A staged configuration change awaiting DNS verification. The currently active configuration keeps serving until the staged one verifies, at which point it is promoted automatically. Submitting another change for the same capability replaces the staged value.
        - `domain` string, required: Hostname the capability uses after the staged change verifies.
        - `status` 'pending' | 'failed' | 'temporary_failure', required: Verification status of the staged change. - `pending`: the DNS records have not been detected yet. - `failed`: the records resolved with wrong values; correct them or submit a different change. - `temporary_failure`: the DNS lookup failed transiently and is queued for retry.
      - `reason` string, nullable: Machine-readable reason code for a failed capability status. Only set when `status` is `failed`. Use this to display a specific message to users rather than a generic failure message. - `tracking_domain_in_use`: the link tracking subdomain is already claimed by another organization.
    - `return_path` DomainCapability, required
      - `status` 'pending' | 'verified' | 'warning' | 'failed' | 'temporary_failure' | 'not_configured', required: Capability verification status. - `pending`: verification has not run, or is currently running. - `verified`: all DNS records for this capability resolved with the expected values. - `warning`: a record for this capability verified before and a recent check no longer matches, but it is still within the grace period. Sending is not yet affected; fix it before the grace period ends. - `failed`: DNS records resolved but at least one value is wrong. Update your DNS to recover. - `temporary_failure`: DNS lookup failed transiently. Verification retries automatically; do not change DNS records unless they are incorrect. - `not_configured`: the capability is not set up on this domain (for example, no tracking domain configured).
      - `domain` string, nullable: Hostname this capability is configured with: the return-path domain, the tracking domain, or the domain where the DMARC policy was found. `null` when not applicable or not configured.
      - `pending` DomainCapabilityPending: A staged configuration change awaiting DNS verification. The currently active configuration keeps serving until the staged one verifies, at which point it is promoted automatically. Submitting another change for the same capability replaces the staged value.
        - `domain` string, required: Hostname the capability uses after the staged change verifies.
        - `status` 'pending' | 'failed' | 'temporary_failure', required: Verification status of the staged change. - `pending`: the DNS records have not been detected yet. - `failed`: the records resolved with wrong values; correct them or submit a different change. - `temporary_failure`: the DNS lookup failed transiently and is queued for retry.
      - `reason` string, nullable: Machine-readable reason code for a failed capability status. Only set when `status` is `failed`. Use this to display a specific message to users rather than a generic failure message. - `tracking_domain_in_use`: the link tracking subdomain is already claimed by another organization.
    - `dmarc` DomainCapability, required
      - `status` 'pending' | 'verified' | 'warning' | 'failed' | 'temporary_failure' | 'not_configured', required: Capability verification status. - `pending`: verification has not run, or is currently running. - `verified`: all DNS records for this capability resolved with the expected values. - `warning`: a record for this capability verified before and a recent check no longer matches, but it is still within the grace period. Sending is not yet affected; fix it before the grace period ends. - `failed`: DNS records resolved but at least one value is wrong. Update your DNS to recover. - `temporary_failure`: DNS lookup failed transiently. Verification retries automatically; do not change DNS records unless they are incorrect. - `not_configured`: the capability is not set up on this domain (for example, no tracking domain configured).
      - `domain` string, nullable: Hostname this capability is configured with: the return-path domain, the tracking domain, or the domain where the DMARC policy was found. `null` when not applicable or not configured.
      - `pending` DomainCapabilityPending: A staged configuration change awaiting DNS verification. The currently active configuration keeps serving until the staged one verifies, at which point it is promoted automatically. Submitting another change for the same capability replaces the staged value.
        - `domain` string, required: Hostname the capability uses after the staged change verifies.
        - `status` 'pending' | 'failed' | 'temporary_failure', required: Verification status of the staged change. - `pending`: the DNS records have not been detected yet. - `failed`: the records resolved with wrong values; correct them or submit a different change. - `temporary_failure`: the DNS lookup failed transiently and is queued for retry.
      - `reason` string, nullable: Machine-readable reason code for a failed capability status. Only set when `status` is `failed`. Use this to display a specific message to users rather than a generic failure message. - `tracking_domain_in_use`: the link tracking subdomain is already claimed by another organization.
    - `tracking` DomainCapability, required
      - `status` 'pending' | 'verified' | 'warning' | 'failed' | 'temporary_failure' | 'not_configured', required: Capability verification status. - `pending`: verification has not run, or is currently running. - `verified`: all DNS records for this capability resolved with the expected values. - `warning`: a record for this capability verified before and a recent check no longer matches, but it is still within the grace period. Sending is not yet affected; fix it before the grace period ends. - `failed`: DNS records resolved but at least one value is wrong. Update your DNS to recover. - `temporary_failure`: DNS lookup failed transiently. Verification retries automatically; do not change DNS records unless they are incorrect. - `not_configured`: the capability is not set up on this domain (for example, no tracking domain configured).
      - `domain` string, nullable: Hostname this capability is configured with: the return-path domain, the tracking domain, or the domain where the DMARC policy was found. `null` when not applicable or not configured.
      - `pending` DomainCapabilityPending: A staged configuration change awaiting DNS verification. The currently active configuration keeps serving until the staged one verifies, at which point it is promoted automatically. Submitting another change for the same capability replaces the staged value.
        - `domain` string, required: Hostname the capability uses after the staged change verifies.
        - `status` 'pending' | 'failed' | 'temporary_failure', required: Verification status of the staged change. - `pending`: the DNS records have not been detected yet. - `failed`: the records resolved with wrong values; correct them or submit a different change. - `temporary_failure`: the DNS lookup failed transiently and is queued for retry.
      - `reason` string, nullable: Machine-readable reason code for a failed capability status. Only set when `status` is `failed`. Use this to display a specific message to users rather than a generic failure message. - `tracking_domain_in_use`: the link tracking subdomain is already claimed by another organization.
    - `inbound` DomainCapability
      - `status` 'pending' | 'verified' | 'warning' | 'failed' | 'temporary_failure' | 'not_configured', required: Capability verification status. - `pending`: verification has not run, or is currently running. - `verified`: all DNS records for this capability resolved with the expected values. - `warning`: a record for this capability verified before and a recent check no longer matches, but it is still within the grace period. Sending is not yet affected; fix it before the grace period ends. - `failed`: DNS records resolved but at least one value is wrong. Update your DNS to recover. - `temporary_failure`: DNS lookup failed transiently. Verification retries automatically; do not change DNS records unless they are incorrect. - `not_configured`: the capability is not set up on this domain (for example, no tracking domain configured).
      - `domain` string, nullable: Hostname this capability is configured with: the return-path domain, the tracking domain, or the domain where the DMARC policy was found. `null` when not applicable or not configured.
      - `pending` DomainCapabilityPending: A staged configuration change awaiting DNS verification. The currently active configuration keeps serving until the staged one verifies, at which point it is promoted automatically. Submitting another change for the same capability replaces the staged value.
        - `domain` string, required: Hostname the capability uses after the staged change verifies.
        - `status` 'pending' | 'failed' | 'temporary_failure', required: Verification status of the staged change. - `pending`: the DNS records have not been detected yet. - `failed`: the records resolved with wrong values; correct them or submit a different change. - `temporary_failure`: the DNS lookup failed transiently and is queued for retry.
      - `reason` string, nullable: Machine-readable reason code for a failed capability status. Only set when `status` is `failed`. Use this to display a specific message to users rather than a generic failure message. - `tracking_domain_in_use`: the link tracking subdomain is already claimed by another organization.
  - `receiving` DomainReceiving, required: Receiving state and whether it is managed from another workspace.
    - `state` 'enabled' | 'disabling' | 'disable_failed' | 'disabled', required: Receiving control state, separate from DNS verification. `enabled` means receiving is configured; check `capabilities.inbound.status` for readiness. `disabling` means a request to turn off receiving is in progress. `disable_failed` means the latest attempt failed and can be retried. `disabled` means receiving is off and no longer blocks deletion.
    - `managed_elsewhere` boolean, required: Receiving is assigned to another workspace in this organization. Its controls are unavailable in the current workspace. An authorized user must open the receiving workspace to turn it off.
  - `dns_records` DNSRecord[], required: The domain's DNS records and their individual verification state, returned in full on both the list and single-domain responses. This is the complete set to publish across DKIM, return-path, DMARC, tracking, and inbound; records for a staged change carry `state: pending`. Inbound MX records are always included as a regional reference, even while receiving is off and `capabilities.inbound.status` is `not_configured`. Their presence alone does not mean receiving is enabled; see `DomainUpdate.inbound`.
    - `type` 'TXT' | 'CNAME' | 'MX', required: The DNS record type to publish, determined by `purpose`. - `TXT`: used for the `dkim` and `dmarc` purposes. - `CNAME`: used for the `return_path` and `tracking` purposes. - `MX`: used for the `inbound_mx` purpose.
    - `name` string, required: The record name: the part you enter in your DNS provider's `Name` or `Host` field, relative to the DNS zone the record belongs in (your registered domain). For a sending domain `mail.acme.com` the DKIM record name is `bird1._domainkey.mail`, entered in the `acme.com` zone. `@` for records at the zone apex.
    - `host` string, required: The fully qualified hostname for this record (for example, `bird1._domainkey.mail.acme.com`).
    - `value` string, required: The value to publish, as entered in your DNS provider's `Value` or `Content` field. For `TXT`, enter the full record content. For `CNAME`, enter the target hostname. For `MX`, enter the priority followed by the mail server hostname.
    - `purpose` 'dkim' | 'return_path' | 'tracking' | 'inbound_mx' | 'dmarc', required: What this record is for. - `dkim`: signs outbound mail and proves domain ownership. - `return_path`: identifies the return-path (bounce) CNAME for sending. - `tracking`: identifies the optional branded open/click tracking CNAME. - `inbound_mx`: identifies the MX record routing mail to us for receiving. Always present wherever inbound is available, as a regional reference, regardless of whether receiving is enabled; publishing it does not enable receiving on its own: see `DomainUpdate.inbound`. It is `optional` until receiving is enabled, and publishing it before then is destructive: on a domain at the zone apex it replaces the MX records that carry the domain's existing mail. - `dmarc`: identifies the DMARC policy record required for sending.
    - `state` 'active' | 'pending' | 'deprecated', required: Lifecycle state of this record. - `active`: the record backs the domain's current configuration. - `pending`: the record belongs to a staged configuration change; publish it to complete the change. - `deprecated`: the record belonged to a previous configuration. Keep it in DNS until `safe_to_remove` is `true`; in-flight mail and previously sent tracked links may still resolve through it.
    - `optional` boolean, required: Whether this record can be skipped. An optional record enables extra functionality (branded tracking, or receiving) rather than sending, so publish one only when you want what it enables. The `inbound_mx` records are optional until you enable receiving on the domain, and publishing one before then changes where mail to the domain is delivered.
    - `status` 'pending' | 'verified' | 'warning' | 'failed', required: Verification status of this record's most recent DNS check. - `pending`: the record has not verified yet; publish it (or correct it) and it verifies on the next check. - `verified`: the most recent check matched the expected value. - `warning`: the record verified before and a recent check no longer matched, but it is still within the grace period. Sending is not yet affected; fix the record before the grace period ends to avoid it being blocked. - `failed`: the record verified before but later checks kept failing past the grace period; the configuration has regressed and needs attention.
    - `error` string, nullable: Human-readable detail for a check that did not pass on this record: what was found in DNS and why it did not match. Also set while `pending` when the record is published but does not match the expected value, which is the case you can act on. `null` when the record is `verified`, when nothing is published at this name yet, or before the first check.
    - `safe_to_remove` boolean, nullable: Only set on `deprecated` records: `true` once the record is no longer referenced by in-flight mail or live tracked links and can be deleted from your DNS. `null` on `active` and `pending` records.
  - `last_checked_at` string, date-time, nullable: When we last checked this domain's DNS records, whether or not the outcome changed. Updated on every verification: your manual refresh and the periodic automatic re-checks alike. `null` if the domain has never been checked.
  - `verified_at` string, date-time, nullable: When the domain's ownership was confirmed: the moment `status` became `verified` via the DKIM record. Unchanged by later re-checks while it stays verified. `null` if the domain has never been verified.
  - `created_at` string, date-time, required: When the domain was added.
  - `updated_at` string, date-time, required: When the domain's configuration was last changed (such as a settings or return-path change). Verification re-checks do not change this; see `last_checked_at` and `verified_at` for verification timing.

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Insufficient permissions
- `404`: Resource not found
- `422`: The request has invalid field values, violates a business rule, or carries a query parameter the endpoint does not declare. Field validation errors use `type: validation_error` and include the affected fields in `details`. Business-rule errors identify the failed rule in `type`.
- `429`: Rate limit exceeded
- `500`: Internal server error
- `503`: The service is temporarily unavailable. If `Retry-After` is present, wait for that delay before retrying; otherwise, retry with exponential backoff. Reuse the same idempotency key and request when retrying a mutation.

---

[API](https://skmtc.dev/messagebird/apis/bird-api.md) · [All operations](https://skmtc.dev/messagebird/apis/bird-api/llms.txt) · [OpenAPI document](https://skmtc.dev/messagebird/apis/bird-api/revisions/3e2a50466454?raw)
