---
title: "Create a domain"
method: POST
path: "/api/v1/domains"
tags: ["Domains"]
---

# Create a domain

`POST /api/v1/domains`

## Request

- Base URL: `https://api.dmarc-examiner.com`
- URL: `https://api.dmarc-examiner.com/api/v1/domains`
- Auth: API key in header `X-API-Key`

Adds a new domain to the organization. The response includes the
`reporting_email` and `dmarc_record` strings — copy them into your DNS
to start receiving DMARC reports.

Returns `400` if the request body is malformed or `name` is missing,
`409 Conflict` if the domain already exists in the organization, and
`402 Payment Required` if the organization has hit its plan domain limit.

## Request body

- CreateDomainRequest
  - `name` string, required: Domain name. Stored lowercased.

## Response `201`

Domain created

- DomainDetail
  - `id` string, uuid, required
  - `name` string, required
  - `status` 'verified' | 'pending' | 'failed', required
  - `verified_at` string, date-time, nullable
  - `last_report_at` string, date-time, nullable
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `reporting_email` string, email, required: Address to set in the `rua=` tag of your DNS DMARC record so reports are delivered to this organization.
  - `dmarc_host` string, required: DNS host where the DMARC record must be published.
  - `dmarc_record` string, required: DMARC record string ready to copy into your DNS as a TXT record. Includes a `ruf=` tag only if the current plan supports forensic reports.

## Other responses

- `400`: Request payload, body field, or query parameter is missing, malformed, outside documented bounds, or fails type/enum validation. Two body shapes can occur: - **Body validation errors** (e.g. missing `name`, wrong type) come from the controller and have the form `{"message": "..."}`. - **Query parameter errors** (e.g. `limit` out of range, `auth_failure` off-enum, `domain_id` not a UUID) flow through the API exception subscriber and add an `error: "bad_request"` machine-readable code: `{"error": "bad_request", "message": "Query parameter \"limit\" must be between 1 and 100, got 999"}`.
- `401`: Authentication failed. Two shapes are possible depending on cause: - **Invalid or revoked key** — body is `{"message": "..."}` only. - **Missing `X-API-Key` header** — body adds an `error: "unauthorized"` machine-readable code. Clients should treat both as the same outcome and read `message` for display.
- `402`: The organization has exhausted a quota on its current plan (e.g. number of domains, number of users). Conceptually distinct from `FeatureNotAvailable` (HTTP 403): the feature IS included in the plan, but the per-organization limit has been reached. Upgrade the plan or remove existing resources before retrying.
- `403`: The organization's current plan does not include the feature required by this endpoint (e.g. `apiAccess`, `forensicReports`, `advancedAlerts`). Distinct from `PlanLimitExceeded` (HTTP 402), which signals a *quota* exhausted on a feature the plan does include. If a customer downgrades to Free, all `/api/v1/*` requests will start returning this response.
- `409`: Resource already exists.
- `429`: Rate limit exceeded.
- `500`: Internal server error.

---

[API](https://skmtc.dev/dmarc-examiner/apis/dmarc-examiner-api.md) · [All operations](https://skmtc.dev/dmarc-examiner/apis/dmarc-examiner-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dmarc-examiner/apis/dmarc-examiner-api/revisions/92f3f57969f5?raw)
