Create an organization role
POST /v1/organizations/{org_id}/roles · permission roles:write
Creates a custom role that exists only in this organization. Organization roles require the org_custom_roles plan feature, cannot be privileged, and cannot be created while the environment's list of permissions allowed for organization roles is empty. The response carries an ETag; the write is audited as role.created. Idempotency-Key is optional.
Request
| Field | Type | Required | Description |
|---|---|---|---|
org_id |
path | yes | Organization ID (org_…). |
key |
string | yes | Lowercase letters, digits, _ and -; 1–64 characters; unique in its scope and immutable. |
name |
string | yes | Display name, up to 128 characters. |
description |
string | no | Up to 1024 characters. |
is_privileged |
boolean | no | Marks a privileged role (not allowed for organization roles). |
assignable_in_self_service |
boolean | no | Defaults to true. |
Response
201 Created with the role.
{
"id": "rol_01j9xr7s1t2w6x8y0z2a4b6c8e",
"organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
"key": "billing-admin",
"name": "Billing admin",
"description": "",
"is_privileged": false,
"assignable_in_self_service": true,
"permission_ids": [],
"created_at": "2026-10-12T09:31:00.123456Z",
"updated_at": "2026-10-12T09:31:00.123456Z",
"version": 1
}
Errors
| HTTP | code | When |
|---|---|---|
| 404 | not_found |
The organization does not exist in this environment. |
| 403 | org_custom_roles_disabled |
Organization roles are turned off in this environment. |
| 403 | plan_feature_unavailable |
The plan does not include organization roles (Business and above). |
| 409 | role_key_conflict |
A role with this key already exists in the scope. |
| 409 | role_limit_reached |
The limit of 1,000 environment roles or 50 roles per organization is reached. |
| 422 | validation_failed |
A field is missing or invalid, or is_privileged is true. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. |
| 429 | rate_limited |
The rate limit was exceeded; retry after the Retry-After period. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry after the Retry-After period. |
Example
curl -i -X POST "https://api.eu.keenauth.com/v1/organizations/org_01j9xk3m7q8r2s4t6v8w0y2z4a/roles" \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"key":"billing-admin","name":"Billing admin"}'