# POST /v1/domains

Add a sending domain

Creates the domain with its own DKIM key and answers the two DNS records to add: a CNAME for the return path and a TXT record for the DKIM key. The domain may send once both records are seen, which Sendora checks on its own and on request. Domains belong to the account: every server sends from them, and an account key manages them; a server key cannot.

Takes an account key (`ak_…`) as a bearer token. TypeScript: `account.domains.create({ domain })`. Python: `account.domains.create(domain=...)`.

## Request body

- `domain` (string, required): The domain mail is sent from, such as example.se; lower-cased and IDNA-encoded.

Example:

```json
{
  "domain": "example.se"
}
```

## Responses

### 201 A sending domain and the two records it needs.

- `domainId` (string (uuid), required)
- `domain` (string, required)
- `verified` (boolean, required): True while both records count as found; only then may mail go out. A lookup that fails at the resolver never changes it, and a record found missing on a verified domain starts a 24-hour warning (failingSince) through which the domain stays verified.
- `createdAt` (string (date-time), required)
- `lastCheckedAt` (string (date-time) or null, required): When the records were last looked up.
- `failingSince` (string (date-time) or null, required): When a check first found a record of this verified domain missing or wrong. Mail keeps going out, the records are looked up hourly, and the first check 24 hours after this that still misses one ends the verification. Null unless the domain is verified and in that warning; verified and each record tell the rest.
- `returnPath` (object, required): The return-path record, which also satisfies SPF.
  - `type` ("CNAME", required)
  - `host` (string, required): The name to create the record under.
  - `value` (string, required): The value the record must hold.
  - `verified` (boolean, required)
  - `verifiedAt` (string (date-time) or null, required)
- `dkim` (object, required): The DKIM public key record.
  - `type` ("TXT", required)
  - `host` (string, required): The name to create the record under.
  - `value` (string, required): The value the record must hold.
  - `verified` (boolean, required)
  - `verifiedAt` (string (date-time) or null, required)

Example:

```json
{
  "domainId": "0d7f6a1e-4c0b-4b7e-9d3c-2a1f5e8b9c01",
  "domain": "example.se",
  "verified": false,
  "createdAt": "2026-09-15T12:00:00.000Z",
  "lastCheckedAt": null,
  "failingSince": null,
  "returnPath": {
    "type": "CNAME",
    "host": "sendora-bounces.example.se",
    "value": "bounces.sendora.se",
    "verified": false,
    "verifiedAt": null
  },
  "dkim": {
    "type": "TXT",
    "host": "s1._domainkey.example.se",
    "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...",
    "verified": false,
    "verifiedAt": null
  }
}
```

## Errors

Every error answers `error`, the code, and `message`, a sentence for a person. A code that adds fields is shown in full below the table.

| Code | Status | Meaning |
| --- | --- | --- |
| `invalid_request` | 400 | The body, the query or a header does not match what the route takes. |
| `unauthorized` | 401 | The key is missing, malformed or revoked. |
| `wrong_token_kind` | 403 | The key is of the other kind: a server key (sk_) where an account key (ak_) is needed, or the reverse. The message names the kind the operation takes. |
| `domain_exists` | 409 | The account already has that domain. |

### `invalid_request`

- `issues` (array of object): One entry per invalid field; absent when a header is wrong.
  - `path` (string, required): The field, dotted, such as to.0.email; empty when the whole body is wrong.
  - `message` (string, required)

Example:

```json
{
  "error": "invalid_request",
  "message": "The request is invalid: to.0: Invalid email address",
  "issues": [
    {
      "path": "to.0",
      "message": "Invalid email address"
    }
  ]
}
```

### `domain_exists`

- `domainId` (string (uuid), required): The id of the domain the account already has.

Example:

```json
{
  "error": "domain_exists",
  "message": "Your account already has that domain.",
  "domainId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
```
