API tokens (owf_…) authenticate the API, the SDKs, the CLI and the MCP server. A token acts with the role of its member, limited to the token's own role and, optionally, to one zone or one client. See Authentication.
| Operation | Endpoint |
|---|---|
| List tokens | GET /v1/orgs/{org}/tokens |
| Create token | POST /v1/orgs/{org}/tokens |
| Revoke token | DELETE /v1/orgs/{org}/tokens/{id} |
List tokens
GET /v1/orgs/{org}/tokensLists the active API tokens of the organization, never their secrets. prefix helps to recognise each one and last_used_at tells when it was last used.
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: Returnsitems, an array of APIToken.
| Field | Type | Description |
|---|---|---|
items[].id | string (uuid) | Id. |
items[].org_id | string (uuid) | Organization id. |
items[].zone_id | string (uuid) | Zone id. |
items[].user_id | string (uuid) | User id of the member. |
items[].name | string | Name. |
items[].role | string | Role. One of owner, admin, tech, readonly. |
items[].prefix | string | First characters of the secret, to recognise it. |
items[].purge_only | boolean | Can only purge its zone's cache. |
items[].created_by | string | Who created it (actor). |
items[].created_at | string (date-time) | Creation time. |
items[].expires_at | string (date-time) | Expiry time. |
items[].last_used_at | string (date-time) | Last use. |
items[].client_id | string (uuid) or null | Client the token is limited to (roles tech and readonly only); null = the whole organization. |
Example
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/tokens" \
-H "Authorization: Bearer $OPENWAF_TOKEN"import { OpenWAF } from "./openwaf";
const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.listTokens();from openwaf import OpenWAF
owf = OpenWAF(base_url="https://dash.openwaf.dev") # token from OPENWAF_TOKEN
result = owf.list_tokens(){
"items": [
{
"id": "11111111-2222-4333-8444-555555555555",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"user_id": "5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
"name": "ci-deploy",
"role": "tech",
"prefix": "owf_8Jx2",
"purge_only": false,
"created_by": "user:5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
"created_at": "2026-10-27T09:30:00Z",
"expires_at": "2027-01-25T09:30:00Z",
"client_id": null
}
]
}Create token
POST /v1/orgs/{org}/tokensCreates an API token for the caller's own member. Without role the token gets the caller's role. It can be limited to one zone (zone_id), to one client (client_id) or to purging its zone's cache (purge_only). See Limit a token.
The secret (owf_…) is returned only in this answer: store it right away.
Required role: readonly or higher. The new token's role cannot be higher than the caller's. Not available to tokens limited to a zone.
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 |
|---|---|---|---|
name | string | Yes | Name. At most 200 characters. |
role | string | No | Role of the token; by default the caller's (tech with purge_only). One of owner, admin, tech, readonly. |
zone_id | string (uuid) | No | Limits the token to that zone. |
expires_in_days | integer | No | Default 90. From 1 to 365. |
purge_only | boolean | No | Token that can only purge its zone's cache (POST cache/purge and GET cache/purges; any other route, MCP included, answers 403 token_scope). Needs zone_id and no client; role tech (default). Default false. |
client_id | string (uuid) | No | Limits the token to the zones of one client (roles tech and readonly only). A client-limited credential only issues tokens of its own client. |
Response
201: Created;secretis shown only once. Returns IssuedToken.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Id. |
org_id | string (uuid) | Organization id. |
zone_id | string (uuid) | Zone id. |
user_id | string (uuid) | User id of the member. |
name | string | Name. |
role | string | Role. One of owner, admin, tech, readonly. |
prefix | string | First characters of the secret, to recognise it. |
purge_only | boolean | Can only purge its zone's cache. |
created_by | string | Who created it (actor). |
created_at | string (date-time) | Creation time. |
expires_at | string (date-time) | Expiry time. |
last_used_at | string (date-time) | Last use. |
client_id | string (uuid) or null | Client the token is limited to (roles tech and readonly only); null = the whole organization. |
secret | string | Shown only once; only its SHA-256 is stored. |
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). |
Example
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/tokens" \
-H "Authorization: Bearer $OPENWAF_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"name": "ci-deploy",
"role": "tech",
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"expires_in_days": 90
}'import { OpenWAF } from "./openwaf";
const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.createToken({
body: {
name: "ci-deploy",
role: "tech",
zone_id: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
expires_in_days: 90
}
});from openwaf import OpenWAF
owf = OpenWAF(base_url="https://dash.openwaf.dev") # token from OPENWAF_TOKEN
result = owf.create_token(
body={
"name": "ci-deploy",
"role": "tech",
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"expires_in_days": 90
},
){
"id": "11111111-2222-4333-8444-555555555555",
"org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
"zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
"user_id": "5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
"name": "ci-deploy",
"role": "tech",
"prefix": "owf_8Jx2",
"purge_only": false,
"created_by": "user:5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
"created_at": "2026-10-27T09:30:00Z",
"expires_at": "2027-01-25T09:30:00Z",
"client_id": null,
"secret": "owf_8Jx2…"
}Revoke token
DELETE /v1/orgs/{org}/tokens/{id}Revokes a token; it stops working at once.
Required role: admin or higher. Organization-wide, or any role to revoke the token making the request.
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). |
id | path | string (uuid) | Yes | Id of the resource. |
Response
204: Revoked. No body.
Errors
| Status | Description |
|---|---|
404 | Not found, or not visible to the token (not_found). |
Example
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/tokens/11111111-2222-4333-8444-555555555555" \
-H "Authorization: Bearer $OPENWAF_TOKEN"import { OpenWAF } from "./openwaf";
const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.revokeToken({
id: "11111111-2222-4333-8444-555555555555"
});from openwaf import OpenWAF
owf = OpenWAF(base_url="https://dash.openwaf.dev") # token from OPENWAF_TOKEN
result = owf.revoke_token(id="11111111-2222-4333-8444-555555555555")