Email checks and Domain Intelligence share one credit balance. See how credits work

Start for free

MX lookup API

Look up MX records and domain mail data through one API.

Request MX records, mail routing and provider information for one domain. The JSON profile also includes SPF/DMARC, known domain signals and IP-to-ASN attribution. Add variant=extended for registry registration data.

The JSON response keeps each observation’s status, source and freshness. Domain Intelligence does not open an SMTP session, verify a mailbox or authenticate a message.

GET for one domain · Structured JSON · Required Idempotency-Key · Shared credits

Request one domain from your backend

The endpoint is GET /v1/domain/{domain}. Send the domain in the path, an API credential in Authorization: Bearer and a required Idempotency-Key. Keep the credential on your server. The request has no body. The optional query parameter variant accepts standard (the default) or extended.

curl -sS https://api.emvero.tech/v1/domain/example.com \
  -H "Authorization: Bearer emv_your_credential" \
  -H "Idempotency-Key: 3f0c9a52-6d1e-4b8e-a7f4-2c51d0e9b6aa"

example.com and the values in the documentation are synthetic. Use a domain, not an email address, URL or IP address. Each request looks up one domain; a subdomain is checked as itself.

For registration data, add ?variant=extended and use a new key for this separate operation:

curl -sS "https://api.emvero.tech/v1/domain/example.com?variant=extended" \
  -H "Authorization: Bearer emv_your_credential" \
  -H "Idempotency-Key: 8c1d2e7a-4b9f-4f0e-9a3c-61e5d2b7c904"
View a complete JSON response · Extended

Synthetic example. Standard returns registration: null and billing.variant: standard. The example below includes registration and costs 2 credits as a new complete Extended operation.

{
  "schema_version": "1",
  "operation_id": "45eb36a9-b4e6-48ac-94a9-0ad145b6cf98",
  "domain": "example.com",
  "ascii_domain": "example.com",
  "status": "complete",
  "generated_at": "2026-10-02T10:00:00Z",
  "mail_routing": {
    "status": "routable",
    "method": "mx",
    "issues": [],
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "dns",
      "source_version": null,
      "observed_at": "2026-10-02T10:00:00Z",
      "expires_at": "2026-10-02T10:05:00Z",
      "stale": false
    }
  },
  "mx": {
    "records": [
      {
        "host": "mx.example.com",
        "priority": 10,
        "provider_id": null
      }
    ],
    "provider_id": null,
    "provider_match": "unknown",
    "truncated": false,
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "dns",
      "source_version": "catalog:17",
      "observed_at": "2026-10-02T10:00:00Z",
      "expires_at": "2026-10-02T10:05:00Z",
      "stale": false
    }
  },
  "email": {
    "classification": {
      "disposable": false,
      "public_provider": false,
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dataset",
        "source_version": "bundle:example-v1",
        "observed_at": null,
        "expires_at": null,
        "stale": false
      }
    },
    "catch_all": {
      "state": "unknown",
      "provider_id": null,
      "meta": {
        "status": "unknown",
        "reason": "not_observed",
        "source": null,
        "source_version": null,
        "observed_at": null,
        "expires_at": null,
        "stale": false
      }
    }
  },
  "email_authentication": {
    "spf": {
      "present": true,
      "syntax": "valid",
      "record": "v=spf1 -all",
      "all_qualifier": "fail",
      "includes": [],
      "redirect": null,
      "evaluation": "not_performed",
      "issues": [],
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dns",
        "source_version": "spf-syntax:1",
        "observed_at": "2026-10-02T10:00:00Z",
        "expires_at": "2026-10-02T10:05:00Z",
        "stale": false
      }
    },
    "dmarc": {
      "present": true,
      "syntax": "valid",
      "record": "v=DMARC1; p=reject",
      "policy_domain": "example.com",
      "inherited": false,
      "published_policy": "reject",
      "effective_policy": "reject",
      "testing": false,
      "adkim": "r",
      "aspf": "r",
      "evaluation": "not_performed",
      "issues": [],
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dns",
        "source_version": "dmarc-rfc9989:1",
        "observed_at": "2026-10-02T10:00:00Z",
        "expires_at": "2026-10-02T10:05:00Z",
        "stale": false
      }
    }
  },
  "network": {
    "mail": [
      {
        "host": "mx.example.com",
        "priority": 10,
        "addresses": [
          {
            "ip": "198.51.100.25",
            "asn": 64500
          },
          {
            "ip": "203.0.113.25",
            "asn": 64511
          },
          {
            "ip": "2001:db8::25",
            "asn": 64500
          }
        ]
      }
    ],
    "web": {
      "host": "example.com",
      "cname_chain": [],
      "addresses": [
        {
          "ip": "198.51.100.80",
          "asn": 64500
        },
        {
          "ip": "2001:db8::80",
          "asn": 64500
        }
      ],
      "truncated": false,
      "edge_provider": null,
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dns",
        "source_version": null,
        "observed_at": "2026-10-02T10:00:00Z",
        "expires_at": "2026-10-02T10:05:00Z",
        "stale": false
      }
    },
    "autonomous_systems": [
      {
        "asn": 64500,
        "handle": "EXAMPLE-ISP",
        "name": "Example Access",
        "country": "DE",
        "type": "isp"
      },
      {
        "asn": 64511,
        "handle": null,
        "name": null,
        "country": null,
        "type": "unknown"
      }
    ],
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "dataset",
      "source_version": "example-routing-dataset",
      "observed_at": "2026-10-02T00:35:16Z",
      "expires_at": null,
      "stale": false
    }
  },
  "registration": {
    "registered_domain": "example.com",
    "registered_at": "2020-10-02T10:00:00Z",
    "age_days": 2191,
    "expires_at": "2027-10-02T10:00:00Z",
    "registrar": "Example Registrar",
    "statuses": [
      "client transfer prohibited"
    ],
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "registry",
      "source_version": "rdap.example.com",
      "observed_at": "2026-10-02T10:00:00Z",
      "expires_at": "2026-11-01T10:00:00Z",
      "stale": false
    }
  },
  "billing": {
    "product": "domain-intelligence",
    "variant": "extended",
    "operation_credits": 2
  }
}

Read routing, MX records and the provider match

mail_routing.status describes the domain’s route. mx.records lists receiving hosts and their priorities. A route does not establish that a named recipient will be accepted. The MX glossary explains the underlying DNS record.

mx.provider_match is matched, mixed, unknown or not_applicable. Matching identifies the visible incoming operator when the preferred hosts agree. That operator can be a filtering gateway rather than the mailbox host. mx.truncated indicates that the record list was shortened. See how to find an email provider for the attribution limits.

email.classification contains known disposable and public-provider signals. A negative classification means no reference-list match, not proof of the opposite. email.catch_all.state reports the state already held for the domain; this lookup makes no new SMTP probe to establish it.

email_authentication contains supported SPF and DMARC publication data. Their evaluation is not_performed: the API does not test a message or sender, discover DKIM keys or recursively evaluate SPF includes. Sending reputation and domain ownership are outside the profile.

Read network and registration fields

network.mail groups public IP addresses and their asn by mail host. network.web contains the requested host, cname_chain, addresses, truncated and edge_provider. The lookup does not add www. or test HTTP availability. A CDN or proxy can hide the origin.

network.autonomous_systems describes each ASN with handle, name, country and type. The country is the network registration country, not IP geolocation. Unknown attribution remains null or unknown. Network failures do not change the overall status or charge; inspect network.meta and network.web.meta separately.

With variant=extended, registration contains registered_domain, registered_at, age_days, expires_at, registrar, statuses and meta. Registry data describes the registrable parent of a subdomain. Missing registration dates make Extended partial; read registration.meta.reason for unavailable, unsupported or omitted data. In Standard, registration is null. Registration age does not establish company age or ownership.

Use per-field metadata with the overall status

A profile has status complete or partial. Read each part’s meta for status, reason, source, observation and expiry times, and whether a value is stale. meta.reason explains why a value could not be established. Retrieval time must not replace the original observation time.

A partial profile can include usable routing while a secondary field is unavailable, stale or truncated. An unknown provider match or an unobserved catch-all state does not by itself mean the whole profile is partial. complete describes lookup coverage, not a positive verdict about the domain.

If the routing source fails, the endpoint can return 503 source_unavailable rather than a guessed no-mail result. Keep request errors separate from the domain observations your application uses.

Retry the same operation with the same key

Within 24 hours of completion, the same key, domain and variant return the saved response byte for byte. A replay does not refresh observations. Reusing a key with a different domain or variant produces 409 idempotency_conflict. If the first attempt is still running, wait for its retry interval and repeat the same request and key.

A complete standard lookup costs 1 shared credit; a complete extended lookup costs 2. Extended costs 1 when the standard observations complete but the registration date is unavailable. Other partial results, saved-answer replays and confirmed refusals cost 0. Network enrichment does not affect the charge. A replay preserves billing.operation_credits; X-Credits-Charged reports the current request.

For commit_unknown or accounting_uncertain, the charge may already have committed. The response omits X-Credits-Charged; absence is not a confirmed zero. Repeat the request with the same key so it reaches the same operation. A new key creates new work.

Choose the domain workflow you need

The Domain Intelligence account page explains how to inspect the profile without writing code. If your only question is whether a domain is configured to receive mail, the free email domain checker provides a narrower answer without an account.

For request validation, the full schema and error handling, use the Domain Intelligence API guide. Neither domain workflow verifies a named mailbox or sends an email.

Questions

Frequently asked.

Which domain fields does the API return?

The response includes routing, MX hosts and priorities, provider matching, disposable/public-provider signals, held catch-all state, SPF/DMARC, mail and web IP addresses, CNAMEs, CDN/proxy attribution and autonomous systems. Extended adds registration data. Each observation retains its source and state.

Does a routable domain mean the mailbox exists?

No. A route describes the domain. This lookup makes no SMTP probe and cannot establish a named mailbox, mailbox ownership or future inbox delivery.

Does the lookup test whether a sender passes SPF or DMARC?

It reads published records and supported syntax or policy fields. Their evaluation is not_performed. It does not evaluate a message, discover DKIM keys or recursively follow SPF includes.

Can I use a partial profile?

Read the status and metadata of the part you need. A partial result may retain a known route while another observation is unavailable or stale. An unknown catch-all state by itself does not necessarily make the whole profile partial.

What do complete lookups and retries cost?

A complete standard lookup costs 1 shared credit; a complete extended lookup costs 2. Extended costs 1 when the standard observations complete but the registration date is unavailable. Other partial results, saved-answer replays and confirmed refusals cost 0. Network enrichment does not affect the charge. A replay preserves billing.operation_credits; X-Credits-Charged reports the current request. For commit_unknown or accounting_uncertain, the charge is uncertain and that header is absent: retry the same key.

Connect the domain lookup

Use the profile in your backend or inspect it in your account.

Confirm a new account for 1,000 shared credits without a card. A complete Standard lookup costs 1 credit; Extended costs 2, or 1 when only its standard observations complete.