# Create a domain

> Add a sending subdomain and get it ready for DNS verification.

`POST https://api-connect.nxiom.com/api/v1/emails/domains`

## Authorization

Requires `email.full_access`.

## Body parameters

| Field | Type | Description |
| --- | --- | --- |
| `domain` | string · required | A valid subdomain such as `mail.example.com`. Root domains are not accepted. |
| `openTracking` | boolean · optional | Defaults to `true`. |

## Request

### cURL

```shell
curl -X POST "https://api-connect.nxiom.com/api/v1/emails/domains" \
  -H "Authorization: Bearer $NEXIOM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "domain": "mail.example.com",
  "openTracking": true
}'
```

### Node.js

```typescript
import { NexiomConnect } from '@nexiom/connect';

const apiKey = process.env.NEXIOM_API_KEY;
if (!apiKey) throw new Error('Set NEXIOM_API_KEY');

const nexiom = new NexiomConnect({ apiKey });

const { data, error } = await nexiom.domains.create({
  domain: 'mail.example.com',
  openTracking: true,
});

if (error) throw new Error(`${error.code}: ${error.message}`);
for (const record of data.dns_records ?? []) {
  console.log(record.record_type, record.name, record.value);
}
```

### PHP

```php
<?php

use Nexiom\Connect\NexiomConnect;

$apiKey = getenv('NEXIOM_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('Set NEXIOM_API_KEY');
}

$nexiom = new NexiomConnect($apiKey);

$domain = $nexiom->domains->create([
    'domain' => 'mail.example.com',
    'openTracking' => true,
]);

foreach ($domain['dns_records'] ?? [] as $record) {
    echo $record['record_type'], ' ', $record['name'], ' ', $record['value'], PHP_EOL;
}
```

## Response

HTTP `200`. The domain is returned under `data`. 

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Domain identifier. |
| `domain` | string | Sending subdomain. |
| `status` | string | `pending`, `verified`, or `failed`. |
| `region` | string | Sending region. |
| `open_tracking` | boolean | Whether open tracking is enabled. |
| `verification_error` | string or null | What still needs attention when the domain is not verified. |
| `verification_attempts` | number | How many verification checks ran. |
| `verification_attempted_at` | string or null | When the last verification check ran. |
| `dns_records` | array | DNS records to publish, each with `id`, `purpose`, `record_type`, `name`, `value`, `priority`, `status`, `required_for_sending`, `last_checked_at`, `error_code`, and `error_message`. |
| `last_verified_at` | string or null | Last successful verification timestamp. |
| `created_at` | string | Creation timestamp. |
| `updated_at` | string | Last change timestamp. |

Publish the returned DNS records with your DNS provider, then [verify the domain](/docs/api/email-domains/verify).

### 200 OK

Example response. Domain and DNS fields shown are illustrative; use the records returned for your own domain.

```json
{
  "data": {
    "id": "domain_example",
    "domain": "mail.example.com",
    "status": "pending",
    "region": "global",
    "open_tracking": true,
    "last_verified_at": null,
    "dns_records": [
      {
        "id": "dns_example",
        "purpose": "dkim",
        "record_type": "CNAME",
        "name": "selector._domainkey.mail.example.com",
        "value": "selector.dkim.example.net",
        "priority": null,
        "status": "pending",
        "required_for_sending": true
      }
    ]
  }
}
```

### 400 Bad Request

The request is invalid. Correct it before retrying; `details` lists the failing fields.

```json
{
  "error": "invalid_argument",
  "message": "Request doesn't match the schema",
  "correlationId": "req_example",
  "details": {
    "context": "body",
    "issues": []
  }
}
```

### 401 Unauthorized

The API key is missing, malformed, revoked, or expired.

```json
{
  "error": "unauthorized",
  "message": "Invalid API key",
  "correlationId": "req_example"
}
```

### 403 Forbidden

The API key lacks a required permission, or its domain restriction does not allow this sender.

```json
{
  "error": "not_allowed",
  "message": "Missing required API key permissions: email.full_access",
  "correlationId": "req_example"
}
```

### 409 Conflict

The resource already exists.

```json
{
  "error": "duplicate_error",
  "message": "Resource already exists",
  "correlationId": "req_example"
}
```

### 429 Too Many Requests

Too many requests. Wait for the `Retry-After` header before retrying. A plan allowance can also return 429 with a `code`; it needs an allowance change, not a retry.

```json
{
  "error": "too_many_requests",
  "code": "RATE_LIMITED",
  "scope": "organization",
  "retryAfterSeconds": 12,
  "message": "Too many requests. Please try again later.",
  "correlationId": "req_example"
}
```

---

Source: https://connect.nxiom.com/docs/api/email-domains/create
