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 | GET /v1/orgs/{org}/brand |
| Set brand | PUT /v1/orgs/{org}/brand |
| Get brand logo | GET /v1/orgs/{org}/brand/logo |
| Upload brand logo | PUT /v1/orgs/{org}/brand/logo |
| Delete brand logo | DELETE /v1/orgs/{org}/brand/logo |
| Get dashboard domain | GET /v1/orgs/{org}/whitelabel/domain |
| Set dashboard domain | PUT /v1/orgs/{org}/whitelabel/domain |
| Delete dashboard domain | DELETE /v1/orgs/{org}/whitelabel/domain |
| Verify dashboard domain | POST /v1/orgs/{org}/whitelabel/domain/verify |
| Get own name servers | GET /v1/orgs/{org}/whitelabel/nameservers |
| Set own name servers | PUT /v1/orgs/{org}/whitelabel/nameservers |
| Delete own name servers | DELETE /v1/orgs/{org}/whitelabel/nameservers |
| Verify own name servers | POST /v1/orgs/{org}/whitelabel/nameservers/verify |
Get brand
GET /v1/orgs/{org}/brandReturns 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.
| 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.
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
"accent": "#0f766e",
"support_email": "[email protected]",
"oauth": false
}Set brand
PUT /v1/orgs/{org}/brandSets 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.
| 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.
| 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.
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": "[email protected]"
}'{
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
"accent": "#0f766e",
"support_email": "[email protected]",
"oauth": false
}Get brand logo
GET /v1/orgs/{org}/brand/logoReturns 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 typeimage/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.
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand/logo" \
-H "Authorization: Bearer $OPENWAF_TOKEN"Upload brand logo
PUT /v1/orgs/{org}/brand/logoUploads 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 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.
| 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.
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{
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
"accent": "#0f766e",
"support_email": "[email protected]",
"oauth": false
}Delete brand logo
DELETE /v1/orgs/{org}/brand/logoRemoves 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.
| 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.
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/brand/logo" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"logo_url": "/v1/brand/logo?v=3f9a1c2b7d4e",
"accent": "#0f766e",
"support_email": "[email protected]",
"oauth": false
}Get dashboard domain
GET /v1/orgs/{org}/whitelabel/domainReturns 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.
| 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.
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"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
PUT /v1/orgs/{org}/whitelabel/domainSets 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. 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.
| 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.
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"
}'{
"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
DELETE /v1/orgs/{org}/whitelabel/domainRemoves 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.
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain" \
-H "Authorization: Bearer $OPENWAF_TOKEN"Verify dashboard domain
POST /v1/orgs/{org}/whitelabel/domain/verifyChecks 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.
| 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.
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/domain/verify" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"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
GET /v1/orgs/{org}/whitelabel/nameserversReturns 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.
| 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.
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"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
PUT /v1/orgs/{org}/whitelabel/nameserversSets 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:
- Create the TXT records listed in
ownership_txt. - 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.
| 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.
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"
]
}'{
"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
DELETE /v1/orgs/{org}/whitelabel/nameserversRemoves 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.
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers" \
-H "Authorization: Bearer $OPENWAF_TOKEN"Verify own name servers
POST /v1/orgs/{org}/whitelabel/nameservers/verifyChecks 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.
| 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.
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/whitelabel/nameservers/verify" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"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"
}