Clients are the end customers of an agency. Each zone may belong to one client, and members, invitations and API tokens limited to a client only see that client's zones. These routes have no SDK methods yet; the examples use curl.
| Operation | Endpoint |
|---|---|
| List clients | GET /v1/orgs/{org}/clients |
| Create client | POST /v1/orgs/{org}/clients |
| Get client | GET /v1/orgs/{org}/clients/{client} |
| Update client | PATCH /v1/orgs/{org}/clients/{client} |
| Delete client | DELETE /v1/orgs/{org}/clients/{client} |
| Set zone client | PATCH /v1/orgs/{org}/zones/{zone} |
List clients
GET /v1/orgs/{org}/clientsLists the clients of the organization with their number of zones.
Required role: readonly or higher. A token limited to a client only sees its own client.
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: Returnsitems, an array of Client.
| Field | Type | Description |
|---|---|---|
items[].id | string (uuid) | Id. |
items[].org_id | string (uuid) | Organization id. |
items[].name | string | Name of the client, unique in the organization. |
items[].contact_email | string | Contact email (may be empty). |
items[].note | string | Internal note of the agency. |
items[].zone_count | integer | Number of zones of the client (in any status). |
items[].created_at | string (date-time) | Creation time. |
items[].updated_at | string (date-time) | Last change. |
Errors
| Status | Description |
|---|---|
403 | The token's role or limits do not allow it (forbidden). |
Example
No SDK method yet: use the HTTP request.
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/clients" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"items": [
{
"id": "a5614527-0ce6-43be-ad1d-d012b7394867",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"contact_email": "[email protected]",
"note": "Managed by the platform team",
"zone_count": 128,
"created_at": "2026-10-27T09:30:00Z",
"updated_at": "2026-10-27T09:30:00Z"
}
]
}Create client
POST /v1/orgs/{org}/clientsCreates a client. name is required and unique in the organization (case-insensitive).
Required role: tech 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: ClientInput.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Required when creating; no commas or line breaks. At most 200 characters. |
contact_email | string (email) | No | At most 320 characters. |
note | string | No | At most 2000 characters. |
Response
201: Created. Returns Client.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Id. |
org_id | string (uuid) | Organization id. |
name | string | Name of the client, unique in the organization. |
contact_email | string | Contact email (may be empty). |
note | string | Internal note of the agency. |
zone_count | integer | Number of zones of the client (in any status). |
created_at | string (date-time) | Creation time. |
updated_at | string (date-time) | Last change. |
Errors
| Status | Description |
|---|---|
400 | Malformed request (bad_request). |
403 | The token's role or limits do not allow it (forbidden). |
409 | conflict: a client with that name already exists. |
422 | Validation error (invalid). |
Example
No SDK method yet: use the HTTP request.
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/clients" \
-H "Authorization: Bearer $OPENWAF_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"name": "Acme Retail",
"contact_email": "[email protected]"
}'{
"id": "a5614527-0ce6-43be-ad1d-d012b7394867",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"contact_email": "[email protected]",
"note": "Managed by the platform team",
"zone_count": 128,
"created_at": "2026-10-27T09:30:00Z",
"updated_at": "2026-10-27T09:30:00Z"
}Get client
GET /v1/orgs/{org}/clients/{client}Returns one client.
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). |
client | path | string (uuid) | Yes | Client id. |
Response
200: Returns Client.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Id. |
org_id | string (uuid) | Organization id. |
name | string | Name of the client, unique in the organization. |
contact_email | string | Contact email (may be empty). |
note | string | Internal note of the agency. |
zone_count | integer | Number of zones of the client (in any status). |
created_at | string (date-time) | Creation time. |
updated_at | string (date-time) | Last change. |
Errors
| Status | Description |
|---|---|
404 | Not found, or not visible to the token (not_found). |
Example
No SDK method yet: use the HTTP request.
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/clients/7c1e3a5d-9b2f-4d6a-8e0c-2f4a6c8e0b1d" \
-H "Authorization: Bearer $OPENWAF_TOKEN"{
"id": "a5614527-0ce6-43be-ad1d-d012b7394867",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"contact_email": "[email protected]",
"note": "Managed by the platform team",
"zone_count": 128,
"created_at": "2026-10-27T09:30:00Z",
"updated_at": "2026-10-27T09:30:00Z"
}Update client
PATCH /v1/orgs/{org}/clients/{client}Changes the name, contact email or note of a client. Fields left out keep their value.
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). |
client | path | string (uuid) | Yes | Client id. |
Request body
Content type application/json. Schema: ClientInput.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Required when creating; no commas or line breaks. At most 200 characters. |
contact_email | string (email) | No | At most 320 characters. |
note | string | No | At most 2000 characters. |
Response
200: Returns Client.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Id. |
org_id | string (uuid) | Organization id. |
name | string | Name of the client, unique in the organization. |
contact_email | string | Contact email (may be empty). |
note | string | Internal note of the agency. |
zone_count | integer | Number of zones of the client (in any status). |
created_at | string (date-time) | Creation time. |
updated_at | string (date-time) | Last change. |
Errors
| Status | Description |
|---|---|
400 | Malformed request (bad_request). |
403 | The token's role or limits do not allow it (forbidden). |
404 | Not found, or not visible to the token (not_found). |
409 | conflict: a client with that name already exists. |
422 | Validation error (invalid). |
Example
No SDK method yet: use the HTTP request.
curl -X PATCH "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/clients/7c1e3a5d-9b2f-4d6a-8e0c-2f4a6c8e0b1d" \
-H "Authorization: Bearer $OPENWAF_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"note": "Renewal in March"
}'{
"id": "a5614527-0ce6-43be-ad1d-d012b7394867",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"contact_email": "[email protected]",
"note": "Managed by the platform team",
"zone_count": 128,
"created_at": "2026-10-27T09:30:00Z",
"updated_at": "2026-10-27T09:30:00Z"
}Delete client
DELETE /v1/orgs/{org}/clients/{client}Deletes a client without zones. Move its zones to another client (or to none) with Set zone client, or delete them, 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). |
client | path | string (uuid) | Yes | Client id. |
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). |
409 | client_has_zones: the client still has zones; move them to another client or delete them first. |
Example
No SDK method yet: use the HTTP request.
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/clients/7c1e3a5d-9b2f-4d6a-8e0c-2f4a6c8e0b1d" \
-H "Authorization: Bearer $OPENWAF_TOKEN"Set zone client
PATCH /v1/orgs/{org}/zones/{zone}Assigns a zone to a client, or to none with null. The client is part of the zone's configuration, so the change creates a new version.
Required role: tech or higher. Organization-wide.
Change controls: dry_run · If-Match (optional) · X-Change-Reason (required)
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). |
zone | path | string (uuid) | Yes | Zone id (see List zones). |
X-Change-Reason | header | string | Yes | Reason of the change: 1-500 UTF-8 characters after trimming spaces, no control characters. If it is missing or invalid: 422 reason_required. 1 to 500 characters. |
If-Match | header | string | No | Expected configuration version, e.g. "12" (W/ accepted). If it is not the current one: 412 version_conflict. |
dry_run | query | string | No | 1/true simulates the change: answers 200 with the plan (Applied) and saves nothing. 0/false accepted; any other value: 400. One of 1, true, 0, false. |
Request body
Content type application/json.
| Field | Type | Required | Description |
|---|---|---|---|
client_id | string (uuid) or null | Yes | Client id, or null so that the zone belongs to no client. |
Response
200: Zone changed (with X-Config-Version and ETag) or, withdry_run, the plan (Applied). Returns Zone or Applied.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Id. |
org_id | string (uuid) | Organization id. |
name | string | Name. |
status | string | One of pending, active, moved, disabled. |
dns_mode | string | delegated: OpenWAF name servers. external: the customer keeps their DNS and points their sites at the edge (CNAME/A). One of delegated, external. Default delegated. |
ns_pair | array of string | Name servers the delegated zones use. Exactly 2 items. |
delegation_checked_at | string (date-time) | Last delegation check. |
delegation | CheckResult or VerifyResult | Last check: CheckResult (delegated) or VerifyResult (external). |
activated_at | string (date-time) | When the zone became active. |
moved_at | string (date-time) | When the delegation stopped pointing to OpenWAF. |
disabled_at | string (date-time) | When the zone was disabled. |
verification | ZoneVerification | |
cname_target | string | External zones only: CNAME target for each site. |
edge_addresses | EdgeAddresses | |
config_version | integer | Current configuration version (also in ETag). |
proxied_names | integer | Names with a proxied record. |
merged_into | string (uuid) | Merged zones only (status disabled): the parent zone. |
merged_at | string (date-time) | Merged zones only; they are purged after 14 days. |
created_at | string (date-time) | Creation time. |
updated_at | string (date-time) | Last change. |
client_id | string (uuid) or null | Client of the organization the zone belongs to; null = none. |
Response headers: ETag, X-Config-Version.
Errors
| Status | Description |
|---|---|
400 | Malformed request (bad_request). |
403 | The token's role or limits do not allow it (forbidden). |
404 | Not found, or not visible to the token (not_found). |
412 | version_conflict: If-Match does not match the current version. |
422 | Validation error (invalid) or missing or invalid reason (reason_required). |
Example
No SDK method yet: use the HTTP request.
curl -X PATCH "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/zones/6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d" \
-H "Authorization: Bearer $OPENWAF_TOKEN" \
-H "X-Change-Reason: Move the zone to its client" \
-H 'If-Match: "12"' \
-H "Content-Type: application/json" \
--data '{
"client_id": "7c1e3a5d-9b2f-4d6a-8e0c-2f4a6c8e0b1d"
}'{
"id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"name": "example.com",
"status": "active",
"dns_mode": "delegated",
"ns_pair": [
"ns1.example-dns.net",
"ns2.example-dns.net"
],
"delegation_checked_at": "2026-10-27T09:00:00Z",
"activated_at": "2026-03-02T11:40:00Z",
"config_version": 12,
"proxied_names": 3,
"client_id": null,
"created_at": "2026-03-02T10:20:00Z",
"updated_at": "2026-10-27T09:00:00Z"
}