# White label

> Brand the dashboard with your name, colour and logo, serve it on your own domain and use your own name servers.

White label lets an agency show the dashboard and its emails with its own brand, serve the dashboard on its own domain (a CNAME to `custom.openwaf.dev`) and publish its zones with its own name servers. These routes have no SDK methods yet; the examples use curl.

| Operation | Endpoint |
|---|---|
| [Get brand](https://developers.openwaf.dev/api/white-label/#get-brand) | `GET /v1/orgs/{org}/brand` |
| [Set brand](https://developers.openwaf.dev/api/white-label/#put-brand) | `PUT /v1/orgs/{org}/brand` |
| [Get brand logo](https://developers.openwaf.dev/api/white-label/#get-brand-logo) | `GET /v1/orgs/{org}/brand/logo` |
| [Upload brand logo](https://developers.openwaf.dev/api/white-label/#put-brand-logo) | `PUT /v1/orgs/{org}/brand/logo` |
| [Delete brand logo](https://developers.openwaf.dev/api/white-label/#delete-brand-logo) | `DELETE /v1/orgs/{org}/brand/logo` |
| [Get dashboard domain](https://developers.openwaf.dev/api/white-label/#get-white-label-domain) | `GET /v1/orgs/{org}/whitelabel/domain` |
| [Set dashboard domain](https://developers.openwaf.dev/api/white-label/#put-white-label-domain) | `PUT /v1/orgs/{org}/whitelabel/domain` |
| [Delete dashboard domain](https://developers.openwaf.dev/api/white-label/#delete-white-label-domain) | `DELETE /v1/orgs/{org}/whitelabel/domain` |
| [Verify dashboard domain](https://developers.openwaf.dev/api/white-label/#verify-white-label-domain) | `POST /v1/orgs/{org}/whitelabel/domain/verify` |
| [Get own name servers](https://developers.openwaf.dev/api/white-label/#get-white-label-nameservers) | `GET /v1/orgs/{org}/whitelabel/nameservers` |
| [Set own name servers](https://developers.openwaf.dev/api/white-label/#put-white-label-nameservers) | `PUT /v1/orgs/{org}/whitelabel/nameservers` |
| [Delete own name servers](https://developers.openwaf.dev/api/white-label/#delete-white-label-nameservers) | `DELETE /v1/orgs/{org}/whitelabel/nameservers` |
| [Verify own name servers](https://developers.openwaf.dev/api/white-label/#verify-white-label-nameservers) | `POST /v1/orgs/{org}/whitelabel/nameservers/verify` |

## Get brand

```http
GET /v1/orgs/{org}/brand
```

Returns the brand of the organization (name, accent colour, logo and support email). Without a brand of its own, the answer is the OpenWAF brand (`org_id` null).

**Required role:** `readonly` or higher.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [Brand](https://developers.openwaf.dev/api/schemas/#brand).

| Field | Type | Description |
|---|---|---|
| `org_id` | string (uuid) or null | Organization of the brand; null = the OpenWAF brand. |
| `name` | string | Name. |
| `logo_url` | string or null | URL of the logo in the dashboard, versioned by its content; null without a logo. |
| `accent` | string | Accent colour `#rrggbb`. |
| `support_email` | string |  |
| `oauth` | boolean | Whether the dashboard on this domain offers Google and GitHub sign-in (only the OpenWAF domain). |

#### Errors

| Status | Description |
|---|---|
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

```json
{
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "name": "example.com",
  "logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
  "accent": "#0f766e",
  "support_email": "support@acme.example",
  "oauth": false
}
```

## Set brand

```http
PUT /v1/orgs/{org}/brand
```

Sets the name, accent colour and support email that the dashboard and its emails show for the organization.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `application/json`. Schema: [BrandInput](https://developers.openwaf.dev/api/schemas/#brand-input).

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | Name shown by the dashboard and the emails; no line breaks, `<` or `>`. At most 100 characters. |
| `accent` | string | Yes | Accent colour `#rrggbb` (lowercased). Pattern `^#[0-9a-f]{6}$`. |
| `support_email` | string (email) | No | Support email shown by the dashboard and the emails. |

#### Response

- `200`: Returns [Brand](https://developers.openwaf.dev/api/schemas/#brand).

| Field | Type | Description |
|---|---|---|
| `org_id` | string (uuid) or null | Organization of the brand; null = the OpenWAF brand. |
| `name` | string | Name. |
| `logo_url` | string or null | URL of the logo in the dashboard, versioned by its content; null without a logo. |
| `accent` | string | Accent colour `#rrggbb`. |
| `support_email` | string |  |
| `oauth` | boolean | Whether the dashboard on this domain offers Google and GitHub sign-in (only the OpenWAF domain). |

#### Errors

| Status | Description |
|---|---|
| `400` | Malformed request (`bad_request`). |
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `422` | Validation error (`invalid`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X PUT "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "name": "Acme Digital",
    "accent": "#0f766e",
    "support_email": "support@acme.example"
  }'
```

```json
{
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "name": "example.com",
  "logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
  "accent": "#0f766e",
  "support_email": "support@acme.example",
  "oauth": false
}
```

## Get brand logo

```http
GET /v1/orgs/{org}/brand/logo
```

Returns the logo of the brand as `image/svg+xml` or `image/png`.

**Required role:** `readonly` or higher.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: The logo. Body of type `image/png`.

#### Errors

| Status | Description |
|---|---|
| `404` | Not found, or not visible to the token (`not_found`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand/logo" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

## Upload brand logo

```http
PUT /v1/orgs/{org}/brand/logo
```

Uploads the logo as the raw request body, `image/svg+xml` or `image/png`, up to 256 KB (PNG up to 4096×4096 pixels). Set the brand with [Set brand](https://developers.openwaf.dev/api/white-label/#put-brand) first.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `image/png`.

At most 262144 characters.

#### Response

- `200`: Returns [Brand](https://developers.openwaf.dev/api/schemas/#brand).

| Field | Type | Description |
|---|---|---|
| `org_id` | string (uuid) or null | Organization of the brand; null = the OpenWAF brand. |
| `name` | string | Name. |
| `logo_url` | string or null | URL of the logo in the dashboard, versioned by its content; null without a logo. |
| `accent` | string | Accent colour `#rrggbb`. |
| `support_email` | string |  |
| `oauth` | boolean | Whether the dashboard on this domain offers Google and GitHub sign-in (only the OpenWAF domain). |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `422` | `invalid`: not a valid SVG or PNG, larger than 256 KB or 4096×4096 pixels, or the brand has no name and colour yet. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X PUT "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand/logo" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: image/png" \
  --data-binary @logo.png
```

```json
{
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "name": "example.com",
  "logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
  "accent": "#0f766e",
  "support_email": "support@acme.example",
  "oauth": false
}
```

## Delete brand logo

```http
DELETE /v1/orgs/{org}/brand/logo
```

Removes the logo of the brand.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [Brand](https://developers.openwaf.dev/api/schemas/#brand).

| Field | Type | Description |
|---|---|---|
| `org_id` | string (uuid) or null | Organization of the brand; null = the OpenWAF brand. |
| `name` | string | Name. |
| `logo_url` | string or null | URL of the logo in the dashboard, versioned by its content; null without a logo. |
| `accent` | string | Accent colour `#rrggbb`. |
| `support_email` | string |  |
| `oauth` | boolean | Whether the dashboard on this domain offers Google and GitHub sign-in (only the OpenWAF domain). |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand/logo" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

```json
{
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "name": "example.com",
  "logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
  "accent": "#0f766e",
  "support_email": "support@acme.example",
  "oauth": false
}
```

## Get dashboard domain

```http
GET /v1/orgs/{org}/whitelabel/domain
```

Returns the organization's own dashboard domain and its status.

**Required role:** `readonly` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [WhiteLabelDomain](https://developers.openwaf.dev/api/schemas/#white-label-domain).

| Field | Type | Description |
|---|---|---|
| `host` | string | Own domain of the dashboard, e.g. `panel.example.com`. |
| `status` | string | One of `pending`, `active`, `error`. |
| `detail` | string | Reason of the `error` status (empty if none). |
| `cname_target` | string | Target of the CNAME record to create (not proxied). |
| `checked_at` | string (date-time) | Last check. |
| `activated_at` | string (date-time) | When the zone became active. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | `not_found`: the organization has no own domain. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

```json
{
  "host": "www.example.com",
  "status": "pending",
  "detail": "",
  "cname_target": "custom.openwaf.dev",
  "checked_at": "2026-10-27T09:30:00Z",
  "activated_at": "2026-10-27T09:30:00Z"
}
```

## Set dashboard domain

```http
PUT /v1/orgs/{org}/whitelabel/domain
```

Sets the domain on which the dashboard is served with the organization's brand. It starts `pending`. Create a CNAME record from that name to `cname_target` (`custom.openwaf.dev`, DNS only, not proxied) and then call [Verify dashboard domain](https://developers.openwaf.dev/api/white-label/#verify-white-label-domain). Changing the domain stops serving the previous one.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `host` | string | Yes | Own domain of the dashboard, e.g. `panel.example.com`. |

#### Response

- `200`: Returns [WhiteLabelDomain](https://developers.openwaf.dev/api/schemas/#white-label-domain).

| Field | Type | Description |
|---|---|---|
| `host` | string | Own domain of the dashboard, e.g. `panel.example.com`. |
| `status` | string | One of `pending`, `active`, `error`. |
| `detail` | string | Reason of the `error` status (empty if none). |
| `cname_target` | string | Target of the CNAME record to create (not proxied). |
| `checked_at` | string (date-time) | Last check. |
| `activated_at` | string (date-time) | When the zone became active. |

#### Errors

| Status | Description |
|---|---|
| `400` | Malformed request (`bad_request`). |
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `409` | `host_taken`: the name belongs to another organization. |
| `422` | Validation error (`invalid`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X PUT "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "host": "panel.acme.example"
  }'
```

```json
{
  "host": "www.example.com",
  "status": "pending",
  "detail": "",
  "cname_target": "custom.openwaf.dev",
  "checked_at": "2026-10-27T09:30:00Z",
  "activated_at": "2026-10-27T09:30:00Z"
}
```

## Delete dashboard domain

```http
DELETE /v1/orgs/{org}/whitelabel/domain
```

Removes the organization's own dashboard domain; the dashboard stops being served on it.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `204`: Deleted. No body.

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

## Verify dashboard domain

```http
POST /v1/orgs/{org}/whitelabel/domain/verify
```

Checks the CNAME record of the dashboard domain. When it points to `cname_target` the domain becomes `active` and the dashboard is served on it with a certificate; otherwise the status is `error` and `detail` says what to fix.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [WhiteLabelDomain](https://developers.openwaf.dev/api/schemas/#white-label-domain).

| Field | Type | Description |
|---|---|---|
| `host` | string | Own domain of the dashboard, e.g. `panel.example.com`. |
| `status` | string | One of `pending`, `active`, `error`. |
| `detail` | string | Reason of the `error` status (empty if none). |
| `cname_target` | string | Target of the CNAME record to create (not proxied). |
| `checked_at` | string (date-time) | Last check. |
| `activated_at` | string (date-time) | When the zone became active. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `409` | `host_taken`: the name belongs to another organization. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain/verify" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

```json
{
  "host": "www.example.com",
  "status": "pending",
  "detail": "",
  "cname_target": "custom.openwaf.dev",
  "checked_at": "2026-10-27T09:30:00Z",
  "activated_at": "2026-10-27T09:30:00Z"
}
```

## Get own name servers

```http
GET /v1/orgs/{org}/whitelabel/nameservers
```

Returns the organization's own name servers, their status, the addresses they must resolve to and the ownership TXT records.

**Required role:** `readonly` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [WhiteLabelNameservers](https://developers.openwaf.dev/api/schemas/#white-label-nameservers).

| Field | Type | Description |
|---|---|---|
| `ns` | array of string | The two own name servers. |
| `status` | string | One of `pending`, `active`, `error`. |
| `detail` | string | Reason of the `error` status (empty if none). |
| `required_ips` | object | Addresses both names must resolve to exactly (A and AAAA). |
| `required_ips.v4` | array of string |  |
| `required_ips.v6` | array of string |  |
| `ownership_txt` | array of object | TXT records proving that the organization controls the domain of its name servers; verification requires them before activation. |
| `ownership_txt[].name` | string | Name. |
| `ownership_txt[].value` | string |  |
| `checked_at` | string (date-time) | Last check. |
| `activated_at` | string (date-time) | When the zone became active. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | `not_found`: the organization has no own name servers. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

```json
{
  "ns": [
    "ns1.example-dns.net",
    "ns2.example-dns.net"
  ],
  "status": "pending",
  "detail": "",
  "required_ips": {
    "v4": [
      "example"
    ],
    "v6": [
      "example"
    ]
  },
  "ownership_txt": [
    {
      "name": "example.com",
      "value": "4f1c2e9a7b3d"
    }
  ],
  "checked_at": "2026-10-27T09:30:00Z",
  "activated_at": "2026-10-27T09:30:00Z"
}
```

## Set own name servers

```http
PUT /v1/orgs/{org}/whitelabel/nameservers
```

Sets two name servers of your own (for example `ns1.example.com` and `ns2.example.com`) to publish the organization's delegated zones instead of the assigned pair. They start `pending`. Before verifying them:

1. Create the TXT records listed in `ownership_txt`.
2. Make both names resolve exactly to the addresses in `required_ips` (A and AAAA; add glue records at the registrar when the names are inside your own domain).

Replacing active name servers makes the zones publish the assigned pair again until the new ones are verified.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `ns` | array of string | Yes | Two different names, e.g. `ns1.example.com` and `ns2.example.com`. Exactly 2 items. |

#### Response

- `200`: Returns [WhiteLabelNameservers](https://developers.openwaf.dev/api/schemas/#white-label-nameservers).

| Field | Type | Description |
|---|---|---|
| `ns` | array of string | The two own name servers. |
| `status` | string | One of `pending`, `active`, `error`. |
| `detail` | string | Reason of the `error` status (empty if none). |
| `required_ips` | object | Addresses both names must resolve to exactly (A and AAAA). |
| `required_ips.v4` | array of string |  |
| `required_ips.v6` | array of string |  |
| `ownership_txt` | array of object | TXT records proving that the organization controls the domain of its name servers; verification requires them before activation. |
| `ownership_txt[].name` | string | Name. |
| `ownership_txt[].value` | string |  |
| `checked_at` | string (date-time) | Last check. |
| `activated_at` | string (date-time) | When the zone became active. |

#### Errors

| Status | Description |
|---|---|
| `400` | Malformed request (`bad_request`). |
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `409` | `host_taken`: a name is used by another organization. |
| `422` | Validation error (`invalid`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X PUT "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "ns": [
      "ns1.acme.example",
      "ns2.acme.example"
    ]
  }'
```

```json
{
  "ns": [
    "ns1.example-dns.net",
    "ns2.example-dns.net"
  ],
  "status": "pending",
  "detail": "",
  "required_ips": {
    "v4": [
      "example"
    ],
    "v6": [
      "example"
    ]
  },
  "ownership_txt": [
    {
      "name": "example.com",
      "value": "4f1c2e9a7b3d"
    }
  ],
  "checked_at": "2026-10-27T09:30:00Z",
  "activated_at": "2026-10-27T09:30:00Z"
}
```

## Delete own name servers

```http
DELETE /v1/orgs/{org}/whitelabel/nameservers
```

Removes the organization's own name servers; its delegated zones publish the assigned pair again.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `204`: Deleted. No body.

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

## Verify own name servers

```http
POST /v1/orgs/{org}/whitelabel/nameservers/verify
```

Checks the ownership TXT records and that both names resolve exactly to `required_ips`. When they do, the name servers become `active` and every delegated zone of the organization publishes them; otherwise the status is `error` and `detail` says what to fix.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [WhiteLabelNameservers](https://developers.openwaf.dev/api/schemas/#white-label-nameservers).

| Field | Type | Description |
|---|---|---|
| `ns` | array of string | The two own name servers. |
| `status` | string | One of `pending`, `active`, `error`. |
| `detail` | string | Reason of the `error` status (empty if none). |
| `required_ips` | object | Addresses both names must resolve to exactly (A and AAAA). |
| `required_ips.v4` | array of string |  |
| `required_ips.v6` | array of string |  |
| `ownership_txt` | array of object | TXT records proving that the organization controls the domain of its name servers; verification requires them before activation. |
| `ownership_txt[].name` | string | Name. |
| `ownership_txt[].value` | string |  |
| `checked_at` | string (date-time) | Last check. |
| `activated_at` | string (date-time) | When the zone became active. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `409` | `host_taken`: a name is used by another organization. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

No SDK method yet: use the HTTP request.

```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers/verify" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

```json
{
  "ns": [
    "ns1.example-dns.net",
    "ns2.example-dns.net"
  ],
  "status": "pending",
  "detail": "",
  "required_ips": {
    "v4": [
      "example"
    ],
    "v6": [
      "example"
    ]
  },
  "ownership_txt": [
    {
      "name": "example.com",
      "value": "4f1c2e9a7b3d"
    }
  ],
  "checked_at": "2026-10-27T09:30:00Z",
  "activated_at": "2026-10-27T09:30:00Z"
}
```
