API keys
Personal API keys let a script act as you outside the browser: a whk_ bearer that carries a subset of your own permissions, changes with your permissions, and dies with your membership. Mint one, list yours, revoke it, and verify what a key can do.
Personal API keys act with their owner's current access, optionally narrowed to selected permissions. Organization API keys use their own permission policies and keep working independently of their creator.
Both use bearer authentication. The verification operation returns the key's current permissions and resource scopes. Key management requires a browser session; keys cannot issue or revoke other keys. Secrets are returned only at creation.
See API keys for choosing a key type, verification and replacement, Personal API keys for membership changes, and Organization API keys for independent access policies.
Preview an MCP client's authorization request
/api/v1/oauth_authorizations/previewSession cookieWhat the consent page shows for the request an MCP client sent the browser to: the client, the permissions it asked for that the person could grant, the person's full vocabulary, and whether keys may be scoped or are allowed at all. The whole request is validated first, so a redirect URI the client did not register is refused before anything is shown.
Request
Request body
One of S256
Space-separated permission keys the client asked for.
One of code
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | OAuthAuthorizationPreview | The consent preview |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
Example
curl -X POST "$WITHHUMAN_URL/api/v1/oauth_authorizations/preview" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Content-Type: application/json" \
-d '{
"client_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"redirect_uri": "https://example.com/webhooks/withhuman",
"state": "string",
"code_challenge": "string",
"code_challenge_method": "S256",
"scope": "string",
"resource": "https://example.com/webhooks/withhuman",
"response_type": "code"
}'{
"client": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "string",
"client_uri": "string",
"redirect_uri": "https://example.com/webhooks/withhuman"
},
"requested_permissions": [
"string"
],
"bearable_permissions": [
{
"key": "pipeline.write",
"area": "pipeline",
"description": "string",
"dangerous": true
}
],
"scoping_enabled": true,
"personal_api_keys_allowed": true
}Approve or decline an MCP client
The person's decision on the consent page. Approval mints a personal API key named after the client, narrowed to the chosen permissions where scoping is available, under the same freshness and MFA rules as a hand-made key, and answers the client's redirect URI carrying a single-use code. Declining answers the redirect URI carrying access_denied. The browser navigates to the answer.
Request
Request body
One of S256
Space-separated permission keys the client asked for.
One of code
The permissions to place on the key; omit to inherit everything the person holds.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | object | Where the browser goes next |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
Example
curl -X POST "$WITHHUMAN_URL/api/v1/oauth_authorizations" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Content-Type: application/json" \
-d '{
"client_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"redirect_uri": "https://example.com/webhooks/withhuman",
"state": "string",
"code_challenge": "string",
"code_challenge_method": "S256",
"scope": "string",
"resource": "https://example.com/webhooks/withhuman",
"response_type": "code",
"approve": true,
"permissions": [
"string"
],
"expires_at": "2026-09-08T12:02:11Z"
}'{
"redirect_url": "https://example.com/webhooks/withhuman"
}List your API keys
/api/v1/me/api_keysSession cookieEvery personal API key you minted, newest first, with its status, and what the create form needs: whether the organization allows personal keys, whether this deployment and plan let a key carry a permission list, and the permissions you could place on one. Never the secret.
Request
No parameters or body.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | MyAPIKeysEnvelope | Your keys |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
The organization's switch.
Whether a key may carry a permission list here. False in the open edition, where keys inherit the member's role.
Example
curl -X GET "$WITHHUMAN_URL/api/v1/me/api_keys" \
-b "withhuman_session=$WITHHUMAN_SESSION"{
"keys": [
{
"grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"usable": true,
"blocked_reason": "organization_inactive",
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"prefix": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31",
"kind": "personal",
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by": {
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"display_name": "string",
"email": "string"
},
"name": "string",
"permissions": [
"string"
],
"assurance_at_issue": "string",
"oauth_client": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "string"
},
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"expires_at": "2026-09-08T12:02:11Z",
"last_used_at": "2026-09-08T12:02:11Z",
"revoked_at": "2026-09-08T12:02:11Z",
"revocation_reason": "manual"
}
],
"personal_api_keys_allowed": true,
"scoping_enabled": true,
"bearable_permissions": [
{
"key": "pipeline.write",
"area": "pipeline",
"description": "string",
"dangerous": true
}
]
}Create an API key
Mints a personal API key bound to your membership. The raw token is returned exactly once; withHuman stores only its hash. Without permissions the key inherits everything you hold, live, so a role change reaches the key on its next request. With permissions (hosted edition) the key is narrowed to that list; every entry must be a permission you hold, and the list can only remove, never add. A key that could decide requests or use a dangerous permission is minted only from a session that passes the organization's re-authentication and MFA rules right now, and the key keeps that session's assurance for later decisions. 403 api_keys_disabled when the organization has turned personal keys off, 403 api_key_scoping_unavailable when this edition cannot scope keys, 403 plan_required when the plan cannot.
Request
Request body
Narrow the key to these permissions. Omit to inherit everything you hold. Each must be a permission you hold; only in the hosted edition.
When the key stops working. Omit for a key that lives until revoked, unless the deployment caps key lifetime.
Response
Response codes
| Status | Body | Description |
|---|---|---|
201 | IssuedAPIKeyEnvelope | The key and, once, its token |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body201
An API key without its secret. Personal prefixes start with whk_; organization prefixes start with who_.
The raw key, shown once: whk_<id>_<secret>.
Example
curl -X POST "$WITHHUMAN_URL/api/v1/me/api_keys" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Content-Type: application/json" \
-d '{
"name": "terraform",
"permissions": [
"pipeline.read",
"pipeline.write",
"pipeline.activate"
],
"expires_at": "2026-09-08T12:02:11Z"
}'{
"key": {
"grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"usable": true,
"blocked_reason": "organization_inactive",
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"prefix": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31",
"kind": "personal",
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by": {
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"display_name": "string",
"email": "string"
},
"name": "string",
"permissions": [
"string"
],
"assurance_at_issue": "string",
"oauth_client": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "string"
},
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"expires_at": "2026-09-08T12:02:11Z",
"last_used_at": "2026-09-08T12:02:11Z",
"revoked_at": "2026-09-08T12:02:11Z",
"revocation_reason": "manual"
},
"token": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31_x5nH9v…"
}Verify an API key
/api/v1/api_keys/verifyAPI keyThe first call a script makes with a fresh key. Answers the key's own row and the permissions it holds right now, after narrowing and your current roles. Only a request authenticated with a key can verify one; a session answers 400.
Request
No parameters or body.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | VerifiedAPIKeyEnvelope | The key behind this request |
400 | ErrorResponse | The request did not authenticate with an API key |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
An API key without its secret. Personal prefixes start with whk_; organization prefixes start with who_.
What the key may do right now, after narrowing and the member's current roles.
Example
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/verify" \
-H "Authorization: Bearer $WITHHUMAN_API_KEY"{
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"key": {
"grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"usable": true,
"blocked_reason": "organization_inactive",
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"prefix": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31",
"kind": "personal",
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by": {
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"display_name": "string",
"email": "string"
},
"name": "string",
"permissions": [
"string"
],
"assurance_at_issue": "string",
"oauth_client": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "string"
},
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"expires_at": "2026-09-08T12:02:11Z",
"last_used_at": "2026-09-08T12:02:11Z",
"revoked_at": "2026-09-08T12:02:11Z",
"revocation_reason": "manual"
},
"effective_permissions": [
"string"
]
}Revoke one of your API keys
/api/v1/me/api_keys/{id}Session cookieRevokes a key you minted. It stops working immediately. Revoking an already revoked key answers 204 again.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid | The API key's id, the part after |
Response
Response codes
| Status | Body | Description |
|---|---|---|
204 | The key is revoked | |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | No such key of yours |
Example
curl -X DELETE "$WITHHUMAN_URL/api/v1/me/api_keys/{id}" \
-b "withhuman_session=$WITHHUMAN_SESSION"List every API key in the organization
The oversight list for owners, admins, and auditors. Both personal and organization keys, newest first, with creator provenance. Never the secret.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
kind | query · enum | Omit to return both key kinds. One of personal, organization |
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | APIKeysEnvelope | The organization's keys |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
Example
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys" \
-b "withhuman_session=$WITHHUMAN_SESSION"{
"keys": [
{
"grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"usable": true,
"blocked_reason": "organization_inactive",
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"prefix": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31",
"kind": "personal",
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by": {
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"display_name": "string",
"email": "string"
},
"name": "string",
"permissions": [
"string"
],
"assurance_at_issue": "string",
"oauth_client": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "string"
},
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"expires_at": "2026-09-08T12:02:11Z",
"last_used_at": "2026-09-08T12:02:11Z",
"revoked_at": "2026-09-08T12:02:11Z",
"revocation_reason": "manual"
}
]
}Inspect an API key
Returns metadata, configured grants, effective organization-key grants, and policy availability. Never returns a secret.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid | The API key's id, the part after |
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | APIKey | Key metadata |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
Current organization-key grants projected from RBAC permission policies. Empty for personal keys.
On detail responses, currently allowed organization-key grants.
Whether the key is active and not blocked by organization policy or status.
One of organization_inactive, api_keys_disabled
Personal keys act as a member; organization keys act as themselves.
One of personal, organization
The member a personal key acts as.
Who minted it. Present on the organization-wide list.
The narrowing list, or null when the key inherits everything its member holds. The key's effective permissions are always this list intersected with the member's current grants.
The assurance of the session that minted the key (strong, single_factor), presented as the key's own when it decides.
The MCP client the key was minted for through the consent page. Absent for a key made by hand.
One of active, expired, revoked
null when the key lives until revoked.
One of manual, membership_deprovisioned
Example
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/{id}" \
-b "withhuman_session=$WITHHUMAN_SESSION"{
"grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"usable": true,
"blocked_reason": "organization_inactive",
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"prefix": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31",
"kind": "personal",
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by": {
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"display_name": "string",
"email": "string"
},
"name": "string",
"permissions": [
"string"
],
"assurance_at_issue": "string",
"oauth_client": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "string"
},
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"expires_at": "2026-09-08T12:02:11Z",
"last_used_at": "2026-09-08T12:02:11Z",
"revoked_at": "2026-09-08T12:02:11Z",
"revocation_reason": "manual"
}Revoke any API key
Revokes anyone's key. It stops working immediately and the audit log records who revoked it.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid | The API key's id, the part after |
Response
Response codes
| Status | Body | Description |
|---|---|---|
204 | The key is revoked | |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | No such key |
Example
curl -X DELETE "$WITHHUMAN_URL/api/v1/api_keys/{id}" \
-b "withhuman_session=$WITHHUMAN_SESSION"Create an organization API keyHosted edition
Delegates explicit scoped grants to an organization-owned key. Requires a fresh human session. The first response shows the secret once; an idempotent retry returns metadata without the secret. Keys survive creator offboarding.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
Idempotency-Keyrequired | header · string | A key of your choosing that identifies this call, so a retry does not act twice. See Idempotency in the API overview. |
Request body
Policies assigned to the key through RBAC. Every permission must allow organization keys and be held by the issuer at each selected resource or wider.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | OrganizationAPIKeyCreated | Already created. secret_available is false; the secret cannot be recovered. |
201 | OrganizationAPIKeyCreated | Created, including the one-time secret. Cache-Control is no-store. |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
409 | ErrorResponse | Idempotency key reused for different intent |
Response body200
Returned only in the first creation response.
Current organization-key grants projected from RBAC permission policies. Empty for personal keys.
On detail responses, currently allowed organization-key grants.
Whether the key is active and not blocked by organization policy or status.
One of organization_inactive, api_keys_disabled
Personal keys act as a member; organization keys act as themselves.
One of personal, organization
The member a personal key acts as.
Who minted it. Present on the organization-wide list.
The narrowing list, or null when the key inherits everything its member holds. The key's effective permissions are always this list intersected with the member's current grants.
The assurance of the session that minted the key (strong, single_factor), presented as the key's own when it decides.
One of active, expired, revoked
null when the key lives until revoked.
One of manual, membership_deprovisioned
Example
curl -X POST "$WITHHUMAN_URL/api/v1/api_keys" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Idempotency-Key: 4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"permission_policies": [
{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
]
}
],
"expires_at": "2026-09-08T12:02:11Z"
}'{
"secret_available": true,
"token": "string",
"grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"effective_grants": [
{
"permission": "request.decide",
"scope_kind": "organization",
"scope_id": "string"
}
],
"usable": true,
"blocked_reason": "organization_inactive",
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"prefix": "whk_4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31",
"kind": "personal",
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by": {
"membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"display_name": "string",
"email": "string"
},
"name": "string",
"permissions": [
"string"
],
"assurance_at_issue": "string",
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"expires_at": "2026-09-08T12:02:11Z",
"last_used_at": "2026-09-08T12:02:11Z",
"revoked_at": "2026-09-08T12:02:11Z",
"revocation_reason": "manual"
}Read organization key creation choicesHosted edition
Grantable permissions and scopes, policy availability, and the deployment lifetime cap. Does not require permission to read the key inventory.
Request
No parameters or body.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | OrganizationAPIKeyOptions | Available creation choices |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
Maximum lifetime as a duration. 0s means no cap.
Example
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/options" \
-b "withhuman_session=$WITHHUMAN_SESSION"{
"organization_api_keys_allowed": true,
"resources": [
{
"id": "string",
"name": "string",
"kind": "organization"
}
],
"permissions": [
{
"key": "request.decide",
"area": "request",
"description": "Approve or deny requests routed to you",
"holders": [
"human"
],
"resource": "organization",
"dangerous": true
}
],
"max_ttl": "string"
}Get organization key permission policiesHosted edition
/api/v1/api_keys/{id}/permission_policiesSession cookieManage permission policies assigned directly to an organization key. Requires a human session, policy authority at each affected scope, and api_key.organization.issue for mutations. Mutations require fresh authentication and the current MFA policy. Expired and revoked keys are read-only.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid |
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | PermissionPoliciesPage | Policy operation completed |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
409 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
Example
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies" \
-b "withhuman_session=$WITHHUMAN_SESSION"{
"name": "string",
"policies": [
{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
],
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"revision": 1,
"resources": [
{
"id": "string",
"name": "string",
"kind": "organization"
}
],
"source": "manual",
"via_team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"via_team_name": "string",
"can_edit": true,
"read_only_reason": "string"
}
],
"resources": [
{
"id": "string",
"name": "string",
"kind": "organization"
}
],
"permissions": [
{
"key": "request.decide",
"area": "request",
"description": "Approve or deny requests routed to you",
"holders": [
"human"
],
"resource": "organization",
"dangerous": true
}
],
"can_create": true,
"is_owner": true,
"read_only_reason": "string"
}Post organization key permission policiesHosted edition
Manage permission policies assigned directly to an organization key. Requires a human session, policy authority at each affected scope, and api_key.organization.issue for mutations. Mutations require fresh authentication and the current MFA policy. Expired and revoked keys are read-only.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid | |
Idempotency-Keyrequired | header · string |
Request body
One of organization, team, agent
Empty for organization scope; otherwise the selected team IDs or agent slugs.
Response
Response codes
| Status | Body | Description |
|---|---|---|
201 | PermissionPolicy | Policy operation completed |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
409 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body201
One of organization, team, agent
Empty for organization scope; otherwise the selected team IDs or agent slugs.
One of manual, directory
Example
curl -X POST "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Idempotency-Key: string" \
-H "Content-Type: application/json" \
-d '{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
]
}'{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
],
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"revision": 1,
"resources": [
{
"id": "string",
"name": "string",
"kind": "organization"
}
],
"source": "manual",
"via_team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"via_team_name": "string",
"can_edit": true,
"read_only_reason": "string"
}Get organization key permission policyHosted edition
/api/v1/api_keys/{id}/permission_policies/{policy_id}Session cookieManage permission policies assigned directly to an organization key. Requires a human session, policy authority at each affected scope, and api_key.organization.issue for mutations. Mutations require fresh authentication and the current MFA policy. Expired and revoked keys are read-only.
Request
Parameters
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | PermissionPolicy | Policy operation completed |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
409 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
One of organization, team, agent
Empty for organization scope; otherwise the selected team IDs or agent slugs.
One of manual, directory
Example
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies/{policy_id}" \
-b "withhuman_session=$WITHHUMAN_SESSION"{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
],
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"revision": 1,
"resources": [
{
"id": "string",
"name": "string",
"kind": "organization"
}
],
"source": "manual",
"via_team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"via_team_name": "string",
"can_edit": true,
"read_only_reason": "string"
}Put organization key permission policyHosted edition
/api/v1/api_keys/{id}/permission_policies/{policy_id}Session cookieRequires permission_policy.writeManage permission policies assigned directly to an organization key. Requires a human session, policy authority at each affected scope, and api_key.organization.issue for mutations. Mutations require fresh authentication and the current MFA policy. Expired and revoked keys are read-only.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid | |
policy_idrequired | path · uuid | |
Idempotency-Keyrequired | header · string |
Request body
One of organization, team, agent
Empty for organization scope; otherwise the selected team IDs or agent slugs.
Required when updating an existing policy.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | PermissionPolicy | Policy operation completed |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
409 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Response body200
One of organization, team, agent
Empty for organization scope; otherwise the selected team IDs or agent slugs.
One of manual, directory
Example
curl -X PUT "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies/{policy_id}" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Idempotency-Key: string" \
-H "Content-Type: application/json" \
-d '{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
],
"revision": 1
}'{
"scope_kind": "organization",
"resource_ids": [
"string"
],
"permissions": [
"string"
],
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"revision": 1,
"resources": [
{
"id": "string",
"name": "string",
"kind": "organization"
}
],
"source": "manual",
"via_team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"via_team_name": "string",
"can_edit": true,
"read_only_reason": "string"
}Delete organization key permission policyHosted edition
/api/v1/api_keys/{id}/permission_policies/{policy_id}Session cookieRequires permission_policy.writeManage permission policies assigned directly to an organization key. Requires a human session, policy authority at each affected scope, and api_key.organization.issue for mutations. Mutations require fresh authentication and the current MFA policy. Expired and revoked keys are read-only.
Request
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | path · uuid | |
policy_idrequired | path · uuid | |
Idempotency-Keyrequired | header · string | |
revisionrequired | query · integer |
Response
Response codes
| Status | Body | Description |
|---|---|---|
204 | Policy operation completed | |
400 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
401 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
403 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
404 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
409 | ErrorResponse | Error response. A 403 from a permission check carries ForbiddenDetails in error.details. |
Example
curl -X DELETE "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies/{policy_id}?revision=1" \
-b "withhuman_session=$WITHHUMAN_SESSION" \
-H "Idempotency-Key: string"