> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reallyquickemails.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Domains

> Register and verify sending domains, and manage their DNS records.

Endpoints for managing sending domains: registration, DNS verification, status, and sender profile.

**Base URL:** `https://api.reallyquickemails.com`

***

## Authentication

All domain endpoints require a Secret Key:

| Header          | Type   | Required | Description                       |
| --------------- | ------ | -------- | --------------------------------- |
| `Authorization` | string | Yes      | `Bearer sk_proj_...`              |
| `Content-Type`  | string | Yes\*    | `application/json` (on POST/PUT). |

***

## Integration flow

If you're automating domain onboarding from your own application, here's the full path:

<Steps>
  <Step title="Register the domain">
    `POST /domains/register` returns all 8 DNS records in `dns_records`, ready to display.
  </Step>

  <Step title="Offer one-click setup">
    `GET /domains/{domain}/domain-connect`. If it returns `supported: true`, redirect the user to `apply_url` and their provider creates the records automatically. Otherwise, show the records for manual setup.
  </Step>

  <Step title="Verify">
    `POST /domains/{domain}/verify` checks the real status and updates the records. Call it when the user says they've configured their DNS.
  </Step>

  <Step title="Confirm before sending">
    Receive `domain.verified` via webhook, or check `GET /domains/{domain}/status`. The domain can send when `can_send: true`.
  </Step>
</Steps>

<Tip>
  **Don't poll — listen for the webhook.** When a domain becomes verified, RQE emits `domain.verified` to your project's webhook URL (and `domain.failed` if verification fails). It fires **once**, on the transition. See [Webhooks](/en/api-reference/webhooks#domainverified-domainfailed).
</Tip>

<Info>
  Pending domains are re-checked on their own, with no call from you: frequently on the first day, spacing out as the registration ages. If your user publishes their DNS days after registering, you still get the webhook. `POST /verify` remains useful for an immediate response when the user says "I've set it up".
</Info>

<Note>
  **SPF and DMARC are checked every 6 hours, not on demand.** A server-side sweep resolves them over DNS and writes their `status` into `dns_records`, so they can come back `verified` or `mismatch` without you calling anything — you no longer need to resolve them yourself. Two caveats: `can_send` ignores them (they drive deliverability and DMARC alignment, not sending permission), and `POST /domains/{domain}/verify` resets both to `not_set` until the next sweep.
</Note>

***

## POST /domains/register

Registers a sending domain: creates the sending identity, generates the DNS records, and creates the sender profile.

### Request Body

| Field          | Type   | Required | Description                                                               |
| -------------- | ------ | -------- | ------------------------------------------------------------------------- |
| `domain`       | string | Yes      | Domain to register (e.g. `mystore.com`).                                  |
| `sender_name`  | string | Yes      | Sender name (e.g. `My Store`).                                            |
| `sender_email` | string | Yes      | Sender email address. Must end in `@{domain}` (e.g. `sales@mystore.com`). |
| `external_key` | string | No       | External key for third-party integrations.                                |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/register \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx" \
      -d '{
        "domain": "mystore.com",
        "sender_name": "My Store",
        "sender_email": "sales@mystore.com"
      }'
    ```
  </Tab>
</Tabs>

**Response** `201 Created`

```json theme={null}
{
  "success": true,
  "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
  "domain": "mystore.com",
  "verification_status": "pending",
  "sender_profile_id": "123e4567-e89b-12d3-a456-426614174000",
  "sender": {
    "from_name": "My Store",
    "from_email": "sales@mystore.com",
    "domain_authenticated": false
  },
  "verification_token": "abcdef1234567890abcdef1234567890",
  "dkim_tokens": ["abc123", "def456", "ghi789"],
  "dns_records": [
    {
      "id": "f1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607",
      "record_type": "TXT",
      "name": "_amazonses",
      "value": "abcdef1234567890abcdef1234567890",
      "purpose": "ses_verification",
      "status": "not_set",
      "ttl_hint": 300
    },
    {
      "id": "a2b3c4d5-e6f7-4081-92a3-b4c5d6e7f809",
      "record_type": "CNAME",
      "name": "abc123._domainkey",
      "value": "abc123.dkim.amazonses.com",
      "purpose": "dkim",
      "status": "not_set",
      "ttl_hint": 1800
    },
    {
      "id": "b3c4d5e6-f708-4192-a3b4-c5d6e7f8091a",
      "record_type": "CNAME",
      "name": "def456._domainkey",
      "value": "def456.dkim.amazonses.com",
      "purpose": "dkim",
      "status": "not_set",
      "ttl_hint": 1800
    },
    {
      "id": "c4d5e6f7-0819-42a3-b4c5-d6e7f8091a2b",
      "record_type": "CNAME",
      "name": "ghi789._domainkey",
      "value": "ghi789.dkim.amazonses.com",
      "purpose": "dkim",
      "status": "not_set",
      "ttl_hint": 1800
    },
    {
      "id": "d5e6f708-192a-43b4-c5d6-e7f8091a2b3c",
      "record_type": "TXT",
      "name": "@",
      "value": "v=spf1 include:amazonses.com ~all",
      "purpose": "spf",
      "status": "not_set",
      "ttl_hint": 300
    },
    {
      "id": "e6f70819-2a3b-44c5-d6e7-f8091a2b3c4d",
      "record_type": "TXT",
      "name": "_dmarc",
      "value": "v=DMARC1; p=none; rua=mailto:d-a1b2c3d4-e5f6-7890-abcd-ef1234567890@dmarc.reallyquickemails.com",
      "purpose": "dmarc",
      "status": "not_set",
      "ttl_hint": 300
    },
    {
      "id": "f708192a-3b4c-45d6-e7f8-091a2b3c4d5e",
      "record_type": "MX",
      "name": "send",
      "value": "10 feedback-smtp.us-east-1.amazonses.com",
      "purpose": "return_path",
      "status": "not_set",
      "ttl_hint": 300
    },
    {
      "id": "0819192a-4c5d-46e7-f809-1a2b3c4d5e6f",
      "record_type": "TXT",
      "name": "send",
      "value": "v=spf1 include:amazonses.com ~all",
      "purpose": "return_path",
      "status": "not_set",
      "ttl_hint": 300
    }
  ]
}
```

Each DNS record includes: `id`, `record_type` (`TXT`, `CNAME` or `MX`), `name`, `value`, `purpose` (`ses_verification`, `dkim`, `spf`, `dmarc`, `return_path`), `status`, and `ttl_hint` (suggested TTL in seconds).

`status` values: `not_set`, `propagating`, `mismatch`, `verified`.

### Generated DNS records

| #   | Type  | Name                 | Purpose             | Notes                                                                      |
| --- | ----- | -------------------- | ------------------- | -------------------------------------------------------------------------- |
| 1   | TXT   | `_amazonses`         | Domain verification | Value generated automatically on registration                              |
| 2-4 | CNAME | `{token}._domainkey` | DKIM                | 3 records, tokens generated automatically                                  |
| 5   | TXT   | `@` (domain root)    | SPF                 | `v=spf1 include:amazonses.com ~all`                                        |
| 6   | TXT   | `_dmarc`             | DMARC               | `v=DMARC1; p=none; rua=mailto:d-{identity_id}@dmarc.reallyquickemails.com` |
| 7   | MX    | `send`               | Return-Path         | `10 feedback-smtp.us-east-1.amazonses.com`                                 |
| 8   | TXT   | `send`               | Return-Path         | `v=spf1 include:amazonses.com ~all`                                        |

<Note>
  The DMARC `rua` points to an RQE mailbox rather than one of your own: that's how we receive your aggregate reports and surface them on the domain detail page. Domains start at `p=none` (monitoring only) so legitimate mail from your other tools isn't sent to spam while alignment settles.
</Note>

<Note>
  Names are relative to the domain. With domain `mystore.com`, the `_amazonses` record is configured as `_amazonses.mystore.com`. Some providers append the domain automatically, so you only enter `_amazonses`.
</Note>

Configure the DNS records with your provider and call `POST /domains/{domain}/verify` to validate. See [Deliverability](/en/concepts/deliverability).

### Error Codes

| Code  | Description                                                                               |
| ----- | ----------------------------------------------------------------------------------------- |
| `400` | Missing required fields, malformed domain, or `sender_email` does not end in `@{domain}`. |
| `401` | Invalid API Key.                                                                          |
| `409` | The domain is attached to another verified sender.                                        |
| `500` | Internal error while registering the domain.                                              |

<Note>
  **Registration is idempotent.** If the domain already has an incomplete record, the operation reconciles it instead of failing: it responds `201` with `reused: true` and the existing DKIM records. Retrying a half-finished registration is safe and won't create duplicates.
</Note>

***

## GET /domains/:domain/dns-records

Returns the stored DNS records with their last known status, without external lookups.

### Path Parameters

| Parameter | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `domain`  | string | Registered domain (e.g. `mystore.com`). |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET https://api.reallyquickemails.com/domains/mystore.com/dns-records \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
  "domain": "mystore.com",
  "verification_status": "pending",
  "dns_records": [
    {
      "id": "f1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607",
      "record_type": "TXT",
      "name": "_amazonses",
      "value": "abcdef1234567890abcdef1234567890",
      "purpose": "ses_verification",
      "status": "not_set",
      "ttl_hint": 300,
      "last_checked_at": null
    },
    {
      "id": "a2b3c4d5-e6f7-4081-92a3-b4c5d6e7f809",
      "record_type": "CNAME",
      "name": "abc123._domainkey",
      "value": "abc123.dkim.amazonses.com",
      "purpose": "dkim",
      "status": "not_set",
      "ttl_hint": 1800,
      "last_checked_at": null
    },
    {
      "id": "d5e6f708-192a-43b4-c5d6-e7f8091a2b3c",
      "record_type": "TXT",
      "name": "@",
      "value": "v=spf1 include:amazonses.com ~all",
      "purpose": "spf",
      "status": "not_set",
      "ttl_hint": 300,
      "last_checked_at": null
    },
    {
      "id": "f708192a-3b4c-45d6-e7f8-091a2b3c4d5e",
      "record_type": "MX",
      "name": "send",
      "value": "10 feedback-smtp.us-east-1.amazonses.com",
      "purpose": "return_path",
      "status": "not_set",
      "ttl_hint": 300,
      "last_checked_at": null
    }
  ]
}
```

Per-record `status`: `not_set`, `propagating`, `mismatch`, or `verified`. `last_checked_at` is `null` until the first verification with `POST /domains/{domain}/verify`.

<Note>
  AWS does not report SPF or DMARC: a sweep of ours resolves them over DNS every 6 hours. After a `POST /verify` they go back to `not_set` until that sweep.
</Note>

### Error Codes

| Code  | Description                      |
| ----- | -------------------------------- |
| `401` | Invalid API Key.                 |
| `404` | Domain not found in the project. |

***

## POST /domains/:domain/verify

Checks the DNS status directly against the sending infrastructure, updates the stored status of the records, and returns whether the domain can send.

### Path Parameters

| Parameter | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `domain`  | string | Registered domain (e.g. `mystore.com`). |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/mystore.com/verify \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
  "domain": "mystore.com",
  "verification_status": "verified",
  "sender_profile": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "from_name": "My Store",
    "from_email": "sales@mystore.com",
    "domain_authenticated": true
  },
  "details": {
    "domain_verification": "Success",
    "dkim_verification": "Success",
    "mail_from_status": "Pending"
  },
  "dns_records": [
    {
      "id": "f1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607",
      "record_type": "TXT",
      "name": "_amazonses",
      "value": "abcdef1234567890abcdef1234567890",
      "purpose": "ses_verification",
      "status": "verified",
      "last_checked_at": "2025-03-10T18:45:00.000Z"
    },
    {
      "id": "a2b3c4d5-e6f7-4081-92a3-b4c5d6e7f809",
      "record_type": "CNAME",
      "name": "abc123._domainkey",
      "value": "abc123.dkim.amazonses.com",
      "purpose": "dkim",
      "status": "verified",
      "last_checked_at": "2025-03-10T18:45:00.000Z"
    },
    {
      "id": "f708192a-3b4c-45d6-e7f8-091a2b3c4d5e",
      "record_type": "MX",
      "name": "send",
      "value": "10 feedback-smtp.us-east-1.amazonses.com",
      "purpose": "return_path",
      "status": "propagating",
      "last_checked_at": "2025-03-10T18:45:00.000Z"
    }
  ],
  "verification_token": "abcdef1234567890abcdef1234567890",
  "dkim_tokens": ["abc123", "def456", "ghi789"],
  "can_send": true
}
```

Verification checks three things:

1. **Domain verification** — The `_amazonses` TXT record is configured.
2. **DKIM** — All 3 DKIM CNAME records are configured and propagated.
3. **MAIL FROM** — The Return-Path records on `send` (MX and TXT) are configured.

Key fields:

| Field                         | Description                                                                                                 |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `verification_status`         | `verified` (domain and DKIM verified), `failed` (a check failed), or `pending`.                             |
| `details.domain_verification` | Raw status of the domain verification: `Success`, `Pending`, `Failed`, `TemporaryFailure`, or `NotStarted`. |
| `details.dkim_verification`   | Raw DKIM status (same values).                                                                              |
| `details.mail_from_status`    | Raw MAIL FROM status (same values).                                                                         |
| `sender_profile`              | The domain's active sender profile, or `null` if none exists.                                               |
| `can_send`                    | `true` when domain and DKIM are verified.                                                                   |

`can_send` is `true` when `details.domain_verification` and `details.dkim_verification` are `Success` (equivalent to `verification_status: "verified"`). MAIL FROM is not required to send, but it improves deliverability.

### Error Codes

| Code  | Description                                          |
| ----- | ---------------------------------------------------- |
| `401` | Invalid API Key.                                     |
| `404` | Domain not found in the project.                     |
| `500` | Error communicating with the sending infrastructure. |

***

## GET /domains/:domain/status

Returns the stored verification status, without querying the sending infrastructure. Fast, ideal for polling from the interface.

### Path Parameters

| Parameter | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `domain`  | string | Registered domain (e.g. `mystore.com`). |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET https://api.reallyquickemails.com/domains/mystore.com/status \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
  "domain": "mystore.com",
  "verification_status": "verified",
  "external_key": null,
  "sender_profile": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "from_name": "My Store",
    "from_email": "sales@mystore.com",
    "domain_authenticated": true
  },
  "dns_records_summary": [
    { "purpose": "ses_verification", "records_count": 1, "all_verified": true },
    { "purpose": "dkim", "records_count": 3, "all_verified": true },
    { "purpose": "spf", "records_count": 1, "all_verified": false },
    { "purpose": "dmarc", "records_count": 1, "all_verified": false },
    { "purpose": "return_path", "records_count": 1, "all_verified": true }
  ],
  "can_send": true,
  "last_verified_at": "2025-03-10T18:45:00.000Z"
}
```

`dns_records_summary` groups the records by purpose: `records_count` is how many there are and `all_verified` indicates whether all of them are `status: "verified"`. `can_send` is `true` when `verification_status` is `verified`. `last_verified_at` is the last update to the domain's status.

### Error Codes

| Code  | Description                      |
| ----- | -------------------------------- |
| `401` | Invalid API Key.                 |
| `404` | Domain not found in the project. |

***

## GET /domains

With the `domain` parameter, looks up **one** by name. Without it, **lists** the project's domains with pagination — so you can reconcile N domains in one request instead of N lookups.

### Query Parameters

| Parameter | Type    | Required | Description                                                            |
| --------- | ------- | -------- | ---------------------------------------------------------------------- |
| `domain`  | string  | No       | Look up a single domain. If present, the other parameters are ignored. |
| `limit`   | integer | No       | Results per page. Default `50`, max `200`.                             |
| `offset`  | integer | No       | Pagination offset. Default `0`.                                        |
| `status`  | string  | No       | Filter by state: `pending`, `verified` or `failed`.                    |

### Example — listing

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.reallyquickemails.com/domains?limit=50&status=verified" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "domains": [
    {
      "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
      "domain": "mystore.com",
      "verification_status": "verified",
      "external_key": null,
      "can_send": true,
      "sender_profile": {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "from_name": "My Store",
        "from_email": "sales@mystore.com",
        "domain_authenticated": true
      },
      "created_at": "2026-03-01T12:00:00.000Z"
    }
  ],
  "total": 128,
  "limit": 50,
  "offset": 0,
  "has_more": true
}
```

Domains come ordered by creation date, newest first. `total` is the full count matching the filter; keep paginating while `has_more` is `true`.

### Example — single lookup

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.reallyquickemails.com/domains?domain=mystore.com" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
  "domain": "mystore.com",
  "verification_status": "verified",
  "external_key": null,
  "can_send": true,
  "sender_profile": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "from_name": "My Store",
    "from_email": "sales@mystore.com",
    "domain_authenticated": true
  },
  "created_at": "2025-03-01T12:00:00.000Z"
}
```

### Error Codes

| Code  | Description                                                      |
| ----- | ---------------------------------------------------------------- |
| `401` | Invalid API Key.                                                 |
| `404` | Domain not found (lookup only — an empty listing returns `200`). |

***

## GET /domains/health

Sending health for all your domains in a single call: which one can send, how its authentication looks, how much it sent, how it bounces, and **what to do about each**.

Built for integrators running several customers. It joins server-side what you'd otherwise piece together by hand across `GET /domains`, the DNS records and `/v1/domain-stats`.

<Info>
  The `issues` field comes back as plain, actionable text — you can forward it straight to your end customer without rewriting it.
</Info>

### Query Parameters

| Parameter | Type    | Default | Description                           |
| --------- | ------- | ------- | ------------------------------------- |
| `days`    | integer | `30`    | Metrics window, between `1` and `90`. |

### Example

```bash theme={null}
curl "https://api.reallyquickemails.com/domains/health" \
  -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
```

```json theme={null}
{
  "success": true,
  "period_days": 30,
  "summary": { "total": 3, "healthy": 1, "warning": 1, "critical": 1 },
  "data": [
    {
      "domain": "customer-ok.com",
      "status": "healthy",
      "can_send": true,
      "sent": 56248,
      "hard_bounce_rate": 0.31,
      "auth": { "ses": "verified", "spf": "verified", "dmarc": "verified", "dkim": "verified" },
      "issues": []
    },
    {
      "domain": "customer-pending.com",
      "status": "warning",
      "can_send": true,
      "sent": 2509,
      "hard_bounce_rate": 0.44,
      "auth": { "ses": "verified", "spf": "verified", "dmarc": "not_set", "dkim": "verified" },
      "issues": [
        "DMARC sin configurar: sin él no hay reportes ni política ante suplantación."
      ]
    },
    {
      "domain": "gmail.com",
      "status": "critical",
      "can_send": true,
      "sent": 14049,
      "hard_bounce_rate": 1.12,
      "auth": { "ses": null, "spf": null, "dmarc": null, "dkim": null },
      "issues": [
        "Se envía desde este dominio pero no está registrado como identidad. Sin verificarlo no hay autenticación posible."
      ]
    }
  ]
}
```

<Note>
  `issues` strings are returned in Spanish today. Match on `status` and `auth.*` rather than on the message text.
</Note>

### Response fields

| Field              | Description                                                                                        |
| ------------------ | -------------------------------------------------------------------------------------------------- |
| `status`           | `healthy` · `warning` · `critical`. See the table below.                                           |
| `can_send`         | Whether the domain has a verified SES identity. **`true` doesn't mean it lands well** — see below. |
| `sent`             | Sends within the requested window (`period_days`).                                                 |
| `hard_bounce_rate` | Percentage of **permanent** bounces. Transient ones don't count.                                   |
| `auth.ses`         | `verified` · `pending` · `failed`, or `null` when there's no domain identity.                      |
| `auth.spf`         | Status of the SPF TXT record as resolved via DNS.                                                  |
| `auth.dmarc`       | Status of the `_dmarc` record. `not_set` when it doesn't exist.                                    |
| `auth.dkim`        | Status of the 3 DKIM CNAMEs. A single missing one keeps it from being `verified`.                  |
| `issues`           | What this domain is missing, as actionable text. Empty when healthy.                               |

Domains come back **sorted by volume**: the ones where fixing pays off most come first.

### How `status` is computed

| Status     | When                                                                                                           |
| ---------- | -------------------------------------------------------------------------------------------------------------- |
| `critical` | The domain can't send, **or** it sends without a verified domain identity, **or** its hard bounce is above 5%. |
| `warning`  | It can send but something's missing: own DKIM, DMARC, or hard bounce crossed 3%.                               |
| `healthy`  | Verified, authenticated, low bounce. `issues` is empty.                                                        |

<Warning>
  **`can_send: true` alongside `status: critical` is the costliest case.** It means email goes out with a `200` and nobody sees an error, but it ships without DKIM on the customer's domain: it gets signed with the platform's shared domain, so their reputation blends with everyone else's and they can't use their own reply domain or tracking domain.

  This shows up when a domain was verified **by email only** (the one-click link) instead of by DNS, or when sending from a domain you don't own such as `gmail.com` — which can't be authenticated at all, since you don't control its DNS.
</Warning>

### Error Codes

| Code  | Description                          |
| ----- | ------------------------------------ |
| `401` | Invalid API Key.                     |
| `500` | Domain health could not be computed. |

***

## GET /domains/:domain/domain-connect

One-click DNS setup. If the domain's DNS provider supports the [Domain Connect](https://www.domainconnect.org/) standard, this returns a signed URL that creates all 8 records automatically: the end user just confirms on their provider's screen, with nothing to copy by hand.

Use it right after `POST /domains/register`. If the provider doesn't support it, fall back to showing the `dns_records` for manual setup.

<Info>
  Measured coverage across real domains: roughly 50% support Domain Connect. Cloudflare is live. Always handle the `supported: false` case.
</Info>

### Path Parameters

| Parameter | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `domain`  | string | Registered domain (e.g. `mystore.com`). |

### Query Parameters

| Parameter      | Type   | Required | Description                                                         |
| -------------- | ------ | -------- | ------------------------------------------------------------------- |
| `redirect_uri` | string | No       | URL the user returns to after applying the records. See note below. |

<Warning>
  `redirect_uri` only accepts ReallyQuickEmails hosts (`app.reallyquickemails.com`) and local development hosts. If you send your own application's domain, the response is `supported: false` with `reason: "invalid_redirect_uri"`. Omit the parameter instead: the `apply_url` still works, the user just lands on their DNS provider's page rather than returning to your app.
</Warning>

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.reallyquickemails.com/domains/mystore.com/domain-connect" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK` — supported provider

```json theme={null}
{
  "supported": true,
  "provider_name": "Cloudflare",
  "zone": "mystore.com",
  "host": "",
  "apply_url": "https://dash.cloudflare.com/domainconnect/v2/domainTemplates/providers/reallyquickemails.com/services/email-sending/apply?domain=mystore.com&sesVerify=...&sig=...&key=_dck1"
}
```

Redirect the user to `apply_url`. Once they confirm, their provider creates the records. Then call `POST /domains/{domain}/verify` to confirm the status.

**Response** `200 OK` — unsupported provider

```json theme={null}
{
  "supported": false,
  "reason": "no_domain_connect",
  "zone": "mystore.com",
  "host": ""
}
```

### Response Fields

| Field           | Description                                                                 |
| --------------- | --------------------------------------------------------------------------- |
| `supported`     | `true` if a one-click flow is available for this domain.                    |
| `apply_url`     | Signed URL to redirect to. Only present when `supported: true`.             |
| `provider_name` | Detected DNS provider name (e.g. `Cloudflare`, `GoDaddy`).                  |
| `zone`          | Detected DNS zone. For subdomains, the root domain holding the NS records.  |
| `host`          | Subdomain prefix within the zone. Empty string when the domain is the root. |
| `reason`        | Why no flow is available. Only present when `supported: false`.             |

### `reason` values

| Value                        | Meaning                                                            |
| ---------------------------- | ------------------------------------------------------------------ |
| `no_zone`                    | Could not determine the domain's DNS zone.                         |
| `no_domain_connect`          | The DNS provider does not advertise Domain Connect support.        |
| `no_sync_flow`               | The provider supports Domain Connect but not the interactive flow. |
| `template_not_onboarded`     | The provider has not enabled the ReallyQuickEmails template.       |
| `identity_missing_tokens`    | The domain has no tokens yet. Register the domain first.           |
| `invalid_redirect_uri`       | The `redirect_uri` you sent is not allowed.                        |
| `signing_key_not_configured` | Service configuration error. Contact support.                      |

<Note>
  `supported: false` is not an error — the response is still `200 OK`. Show the DNS records from `GET /domains/{domain}/dns-records` so the user can configure them manually.
</Note>

### Error Codes

| Code  | Description                      |
| ----- | -------------------------------- |
| `401` | Invalid API Key.                 |
| `404` | Domain not found in the project. |
| `500` | Error querying the DNS provider. |

***

## POST /domains/:domain/recreate

Deletes and recreates the domain's sending identity. Useful when DKIM gets stuck in a failed state.

### Path Parameters

| Parameter | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `domain`  | string | Registered domain (e.g. `mystore.com`). |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/mystore.com/recreate \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "identity_id": "8a1f6e2c-3b4d-4f5a-9c6e-7d8f9a0b1c2d",
  "domain": "mystore.com",
  "verification_status": "pending",
  "verification_token": "abcdef1234567890abcdef1234567890",
  "dkim_tokens": ["abc123", "def456", "ghi789"],
  "dns_records": [
    {
      "id": "f1a2b3c4-d5e6-4f70-8a91-b2c3d4e5f607",
      "record_type": "TXT",
      "name": "_amazonses",
      "value": "abcdef1234567890abcdef1234567890",
      "purpose": "ses_verification",
      "status": "not_set",
      "ttl_hint": 300
    }
  ],
  "message": "Domain identity recreated in SES. DNS records may already be propagated - verify in a few seconds."
}
```

It keeps the domain and sender profile, regenerates the DNS records, and resets `verification_status` to `pending`. Then call `POST /domains/{domain}/verify`. If the records were already propagated, verification can complete in seconds.

### Error Codes

| Code  | Description                            |
| ----- | -------------------------------------- |
| `401` | Invalid API Key.                       |
| `404` | Domain not found in the project.       |
| `500` | Error recreating the sending identity. |

***

## DELETE /domains/:domain

Removes the domain from the sending infrastructure and deactivates its sender profile.

### Path Parameters

| Parameter | Type   | Description                            |
| --------- | ------ | -------------------------------------- |
| `domain`  | string | Domain to delete (e.g. `mystore.com`). |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X DELETE https://api.reallyquickemails.com/domains/mystore.com \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "domain": "mystore.com",
  "message": "Domain and associated sender profile removed"
}
```

The same domain can be registered again later.

<Warning>
  After deleting it, you will need to register the domain and configure the DNS records again to send from it.
</Warning>

### Error Codes

| Code  | Description                      |
| ----- | -------------------------------- |
| `401` | Invalid API Key.                 |
| `404` | Domain not found in the project. |

***

## PUT /domains/:domain/sender

Updates the sender profile associated with a domain.

### Path Parameters

| Parameter | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `domain`  | string | Associated domain (e.g. `mystore.com`). |

### Request Body

| Field          | Type   | Required | Description                                    |
| -------------- | ------ | -------- | ---------------------------------------------- |
| `sender_name`  | string | Yes      | Visible sender name.                           |
| `sender_email` | string | Yes      | Sender email address. Must end in `@{domain}`. |
| `reply_email`  | string | No       | Email address for replies (Reply-To).          |

### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X PUT https://api.reallyquickemails.com/domains/mystore.com/sender \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx" \
      -d '{
        "sender_name": "My Store Team",
        "sender_email": "sales@mystore.com",
        "reply_email": "support@mystore.com"
      }'
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "sender_profile_id": "123e4567-e89b-12d3-a456-426614174000",
  "from_name": "My Store Team",
  "from_email": "sales@mystore.com",
  "domain_authenticated": true
}
```

<Note>
  The `reply_email` field is saved but not included in the response.
</Note>

### Error Codes

| Code  | Description                                                                           |
| ----- | ------------------------------------------------------------------------------------- |
| `400` | Missing `sender_name` or `sender_email`, or `sender_email` does not match the domain. |
| `401` | Invalid API Key.                                                                      |
| `404` | Domain or sender profile not found in the project.                                    |

***

## Reply domain (clean Reply-To, token-less)

Configure a **branded reply domain** per project (`reply.yourdomain.com`) so the Reply-To of API sends comes out clean —`localpart@reply.yourdomain.com`— instead of the encoded token. Sending and reply resolution are automatic once verified. Without a reply domain configured, the usual token is used. How it affects the webhook: [Webhooks · reply domain](/en/api-reference/webhooks#branded-reply-domain-optional-token-less).

```mermaid theme={null}
flowchart LR
  A[POST /domains/reply] --> B[Publish TXT + MX in DNS]
  B --> C[POST /domains/reply/verify]
  C --> D{SES verified?}
  D -->|yes| E[Clean Reply-To active]
  E --> F[Recipient reply]
  F --> G[Webhook email.inbound]
```

<Info>
  **Model for integrators (several reply domains per project).** The reply domain belongs to the project of the API key you call with, and **a project can have several**: each send resolves the one matching the sender's domain.

  To offer clean replies to **your own clients** from a single project, register each one's domain with your key: `POST /domains/reply { "domain": "phrasso.com" }` and that client's replies arrive at `name@reply.phrasso.com`. To verify a specific one, pass `domain` in the body of `POST /domains/reply/verify`.

  You can also give each client their own project and key — see [Partner quickstart](/en/guides/partner-quickstart) for when each model fits.
</Info>

### POST /domains/reply

Registers the reply domain: verifies the identity in SES for **receiving** and returns the 2 DNS records the client must publish.

#### Request Body

| Field    | Type   | Required | Description                                                               |
| -------- | ------ | -------- | ------------------------------------------------------------------------- |
| `domain` | string | Yes      | The client's domain (e.g. `phrasso.com`). RQE builds `reply.phrasso.com`. |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/reply \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx" \
      -H "Content-Type: application/json" \
      -d '{ "domain": "phrasso.com" }'
    ```
  </Tab>
</Tabs>

**Response** `201 Created`

```json theme={null}
{
  "success": true,
  "reply_domain": "reply.phrasso.com",
  "reply_domain_status": "pending",
  "dns_records": [
    { "record_type": "TXT", "name": "_amazonses.reply.phrasso.com", "value": "<token>", "purpose": "ses_verification", "ttl_hint": 300 },
    { "record_type": "MX", "name": "reply.phrasso.com", "value": "inbound-smtp.us-east-1.amazonaws.com", "priority": 10, "purpose": "reply_inbound", "ttl_hint": 300 }
  ],
  "message": "Publish these 2 records in the domain's DNS, then call POST /domains/reply/verify."
}
```

The client publishes those 2 records (SES verification TXT + MX that routes replies to RQE's inbound). Then calls **verify**.

### POST /domains/reply/verify

Queries SES and marks the reply domain `verified` once the TXT has propagated. From then on, the project's API sends go out with the clean Reply-To.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/reply/verify \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "success": true,
  "reply_domain": "reply.phrasso.com",
  "reply_domain_status": "verified",
  "ses_status": "Success",
  "can_receive": true
}
```

`reply_domain_status`: `pending` (not yet verified) · `verified` (in use) · `failed`. `can_receive` is `true` when SES can receive for the domain.

### GET /domains/reply

Status and DNS records of the project's reply domain. `reply_domain: null` if none is configured.

```bash theme={null}
curl https://api.reallyquickemails.com/domains/reply \
  -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
```

### DELETE /domains/reply

Removes the reply domain (takes it out of inbound routing, deletes the SES identity, clears the project). Sends revert to the token Reply-To.

```bash theme={null}
curl -X DELETE https://api.reallyquickemails.com/domains/reply \
  -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
```

***

## Tracking domain (click links on your own domain)

Wrap click-tracking links with **your own subdomain** (`links.yourdomain.com`) instead of RQE's shared one. Isolates tracking reputation and aligns links with your `From`. Configured with a single **CNAME** record.

<Info>
  The tracking domain is **changed, never deleted**: links in already-sent emails depend on the domain still resolving. That's why there's no `DELETE` endpoint — to migrate, publish the new CNAME and call `PUT` with the new domain.
</Info>

These endpoints live under `/api/projects/:projectId`. The `:projectId` is your **project UUID** —the `project_id` returned by any send response— and must match the project of your API key.

### GET /api/projects/:projectId/tracking-domain

Current tracking domain status for the project.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl https://api.reallyquickemails.com/api/projects/:projectId/tracking-domain \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "domain": "links.yourdomain.com",
  "status": "verified",
  "verified_at": "2026-07-20T12:00:00.000Z",
  "cname": { "name": "links.yourdomain.com", "target": "track.reallyquickemails.com" }
}
```

`domain`, `status` and `cname` are `null` if none is configured.

### PUT /api/projects/:projectId/tracking-domain

Set or change the tracking domain. Stays `pending` until verified. Must be a subdomain you own (e.g. `links.yourdomain.com`), never an RQE domain.

#### Request Body

| Field    | Type   | Required | Description                                       |
| -------- | ------ | -------- | ------------------------------------------------- |
| `domain` | string | Yes      | A subdomain you own, e.g. `links.yourdomain.com`. |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X PUT https://api.reallyquickemails.com/api/projects/:projectId/tracking-domain \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx" \
      -H "Content-Type: application/json" \
      -d '{ "domain": "links.yourdomain.com" }'
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "domain": "links.yourdomain.com",
  "status": "pending",
  "cname": { "name": "links.yourdomain.com", "target": "track.reallyquickemails.com" },
  "tls_registered": true
}
```

Publish the **CNAME** `links.yourdomain.com → track.reallyquickemails.com` in your DNS, then call **verify**.

| Code  | Error                     | Reason                                             |
| ----- | ------------------------- | -------------------------------------------------- |
| `400` | `INVALID_DOMAIN`          | Not a valid subdomain, or an RQE domain.           |
| `502` | `TLS_REGISTRATION_FAILED` | Could not register the domain to issue TLS. Retry. |

### POST /api/projects/:projectId/tracking-domain/verify

Checks DNS and marks `verified` once the CNAME resolves to our target (supports Cloudflare CNAME flattening by comparing A records).

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/api/projects/:projectId/tracking-domain/verify \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200 OK`

```json theme={null}
{
  "domain": "links.yourdomain.com",
  "status": "verified",
  "verified": true,
  "detail": "cname",
  "cname": { "name": "links.yourdomain.com", "target": "track.reallyquickemails.com" }
}
```

`verified: false` with `status: "pending"` if DNS hasn't propagated yet (`detail` explains why). Returns `404 NO_DOMAIN` if no tracking domain is configured.

***

## Email Verification (Magic Link)

An alternative to full domain verification: verify an individual email as a sender without configuring DNS. A verification email is sent; clicking the link verifies the email for sending.

<Note>
  It is faster but does not include DKIM/SPF. For better deliverability, verify the full domain.
</Note>

When the status changes (from `pending` to `verified` or `failed`), RQE emits the `sender.verified` or `sender.failed` webhook. See [Webhooks](/en/api-reference/webhooks).

***

### POST /domains/verify-email

Starts the verification of an email as a sender by sending it a verification link.

#### Request Body

| Field          | Type   | Required | Description                    |
| -------------- | ------ | -------- | ------------------------------ |
| `sender_email` | string | Yes      | Email to verify as a sender.   |
| `sender_name`  | string | Yes      | Visible sender name.           |
| `external_key` | string | No       | External key for integrations. |

#### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/verify-email \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx" \
      -H "Content-Type: application/json" \
      -d '{
        "sender_email": "sales@gmail.com",
        "sender_name": "My Company"
      }'
    ```
  </Tab>
</Tabs>

**Response** `201`

```json theme={null}
{
  "success": true,
  "identity_id": "550e8400-e29b-41d4-a716-446655440000",
  "sender_email": "sales@gmail.com",
  "verification_status": "pending",
  "sender_profile_id": "123e4567-e89b-12d3-a456-426614174000",
  "sender": {
    "from_name": "My Company",
    "from_email": "sales@gmail.com",
    "email_verified": false,
    "domain_authenticated": false
  },
  "message": "Verification email sent. The sender must click the link in the email to verify."
}
```

The sender will receive an email with a link. Clicking it verifies their email.

#### Errors

| Code  | Description                                                      |
| ----- | ---------------------------------------------------------------- |
| `400` | Missing `sender_email` or `sender_name`, or invalid email format |
| `401` | Invalid API Key                                                  |
| `409` | Email already registered in this project                         |

***

### GET /domains/verify-email/status

Queries the verification status of an email against the sending infrastructure in real time.

#### Query Parameters

| Parameter | Type   | Required | Description     |
| --------- | ------ | -------- | --------------- |
| `email`   | string | Yes      | Email to query. |

#### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl "https://api.reallyquickemails.com/domains/verify-email/status?email=sales@gmail.com" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200`

```json theme={null}
{
  "success": true,
  "identity_id": "550e8400-e29b-41d4-a716-446655440000",
  "sender_email": "sales@gmail.com",
  "verification_status": "verified",
  "sender_profile": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "from_name": "My Company",
    "from_email": "sales@gmail.com",
    "email_verified": true,
    "domain_authenticated": false
  },
  "can_send": true
}
```

`sender_profile` can be `null` if no active sender profile exists. `can_send` is `true` when `verification_status` is `verified`.

#### Verification statuses

| Status     | Description                                              |
| ---------- | -------------------------------------------------------- |
| `pending`  | Verification email sent, waiting for the sender to click |
| `verified` | Sender verified, ready to send                           |
| `failed`   | Verification failed                                      |

#### Errors

| Code  | Description                         |
| ----- | ----------------------------------- |
| `400` | `email query parameter is required` |
| `401` | Invalid API Key                     |
| `404` | Email not found in the project      |

***

### POST /domains/verify-email/resend

Resends the verification email to the sender. Only valid while verification is `pending`.

#### Request Body

| Field          | Type   | Required | Description         |
| -------------- | ------ | -------- | ------------------- |
| `sender_email` | string | Yes      | Email to resend to. |

#### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.reallyquickemails.com/domains/verify-email/resend \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx" \
      -H "Content-Type: application/json" \
      -d '{
        "sender_email": "sales@gmail.com"
      }'
    ```
  </Tab>
</Tabs>

**Response** `200`

```json theme={null}
{
  "success": true,
  "message": "Verification email resent",
  "sender_email": "sales@gmail.com"
}
```

#### Errors

| Code  | Description                                                       |
| ----- | ----------------------------------------------------------------- |
| `400` | Missing `sender_email`, or verification is not in `pending` state |
| `401` | Invalid API Key                                                   |
| `404` | Email not found in the project                                    |

***

### DELETE /domains/verify-email

Deletes an email verified as a sender; the same email can be registered again later.

#### Query Parameters

| Parameter | Type   | Required | Description      |
| --------- | ------ | -------- | ---------------- |
| `email`   | string | Yes      | Email to delete. |

#### Example

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X DELETE "https://api.reallyquickemails.com/domains/verify-email?email=sales@gmail.com" \
      -H "Authorization: Bearer sk_proj_xxxxxxxxxxxx"
    ```
  </Tab>
</Tabs>

**Response** `200`

```json theme={null}
{
  "success": true,
  "sender_email": "sales@gmail.com",
  "message": "Email identity and associated sender profile removed"
}
```

#### Errors

| Code  | Description                         |
| ----- | ----------------------------------- |
| `400` | `email query parameter is required` |
| `401` | Invalid API Key                     |
| `404` | Email not found in the project      |
