# Inspect a domain's mail setup

`GET /api/v1/email/domain/{domain}`

- Authentication: Secret API key as a bearer token
- Billing: 1 credit only when the domain accepts mail (`mx_found` true) and the lookup is fresh; invalid or dead domains and 7-day repeats are free.
- Group: Domain

The domain-level signals of an email lookup, answered once for a whole domain: whether it can receive mail (MX records, or the RFC 5321 implicit fallback), who runs its mail, whether it publishes SPF and which DMARC policy, when it was registered, whether it is on the disposable or free-provider lists, and whether any address there has answered catch-all within the last week.

Invalid input is an answer, not a validation error: a string that is not a hostname answers `200` with `valid: false` and every other field null. A domain with no usable mail server is free. The per-account 7-day repeat cache applies.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `domain` | path | string | yes | The domain to inspect. Lowercased and converted to punycode before checking. At most 254 characters. |

## Example request

```bash
curl https://spaw.co/api/v1/email/domain/acme.com \
  -H "Authorization: Bearer sk_live_…"
```

## Responses

### 200 — The domain's signals; `valid: false` for input that is not a hostname.

```json
{
    "success": true,
    "data": {
        "domain": "acme.com",
        "valid": true,
        "mx_found": true,
        "mx_implicit": false,
        "catch_all": null,
        "mx_provider": "google",
        "has_spf": true,
        "dmarc_policy": "reject",
        "domain_registered_at": "1998-03-12",
        "domain_age_days": 10402,
        "disposable": false,
        "free_provider": false,
        "sources": [
            {
                "dataset": "live-dns",
                "version": "2026-09-03"
            },
            {
                "dataset": "disposable-domains",
                "version": "2026-09-01"
            },
            {
                "dataset": "free-provider-domains",
                "version": "2026-09-01"
            },
            {
                "dataset": "mx-provider-patterns",
                "version": "2026-08-30"
            },
            {
                "dataset": "rdap-registration",
                "version": "2026-09-03"
            }
        ]
    },
    "meta": {
        "credits_used": 1,
        "credits_remaining": 8,
        "cache_hit": false,
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 401 — The key is missing, malformed, or revoked.

```json
{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 402 — The balance is empty. The lookup did not run.

```json
{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your credit balance is empty.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 429 — Over 5 requests per second for the key. Retry after the limit resets.

```json
{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

## Error codes

- `UNAUTHENTICATED` — https://spaw.co/docs/errors/UNAUTHENTICATED
- `INSUFFICIENT_CREDITS` — https://spaw.co/docs/errors/INSUFFICIENT_CREDITS
- `RATE_LIMITED` — https://spaw.co/docs/errors/RATE_LIMITED

---

Canonical page: https://spaw.co/docs/api/domain-intelligence · OpenAPI document: https://spaw.co/openapi.json · All endpoints: https://spaw.co/docs/api
