Documentation
DocsAPI reference

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.

Updated Sep 24, 2026

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

POST/api/v1/oauth_authorizations/previewSession cookieSelf-service

What 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

client_iduuidrequired
redirect_uriurirequired
statestring
code_challengestringrequired

One of S256

scopestring

Space-separated permission keys the client asked for.

One of code

Response

Response codes

StatusBodyDescription
200OAuthAuthorizationPreview

The consent preview

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

clientobjectrequired
requested_permissionsarray<string>required
scoping_enabledbooleanrequired

Example

POST /api/v1/oauth_authorizations/preview
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"
}'
200 response
{
  "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

POST/api/v1/oauth_authorizationsSession cookieRequires api_key.issue

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

client_iduuidrequired
redirect_uriurirequired
statestring
code_challengestringrequired

One of S256

scopestring

Space-separated permission keys the client asked for.

One of code

approvebooleanrequired
permissionsarray<string>

The permissions to place on the key; omit to inherit everything the person holds.

expires_atdate-time

Response

Response codes

StatusBodyDescription
200object

Where the browser goes next

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

redirect_urlurirequired

Example

POST /api/v1/oauth_authorizations
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"
}'
200 response
{
  "redirect_url": "https://example.com/webhooks/withhuman"
}

List your API keys

GET/api/v1/me/api_keysSession cookieSelf-service

Every 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

StatusBodyDescription
200MyAPIKeysEnvelope

Your keys

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

keysarray<APIKey>required

The organization's switch.

scoping_enabledbooleanrequired

Whether a key may carry a permission list here. False in the open edition, where keys inherit the member's role.

Example

GET /api/v1/me/api_keys
curl -X GET "$WITHHUMAN_URL/api/v1/me/api_keys" \
  -b "withhuman_session=$WITHHUMAN_SESSION"
200 response
{
  "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

POST/api/v1/me/api_keysSession cookieRequires api_key.issue

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

namestringrequired
permissionsarray<string>

Narrow the key to these permissions. Omit to inherit everything you hold. Each must be a permission you hold; only in the hosted edition.

expires_atdate-time

When the key stops working. Omit for a key that lives until revoked, unless the deployment caps key lifetime.

Response

Response codes

StatusBodyDescription
201IssuedAPIKeyEnvelope

The key and, once, its token

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body201

keyAPIKeyrequired

An API key without its secret. Personal prefixes start with whk_; organization prefixes start with who_.

tokenstringrequired

The raw key, shown once: whk_<id>_<secret>.

Example

POST /api/v1/me/api_keys
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"
}'
201 response
{
  "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

GET/api/v1/api_keys/verifyAPI keySelf-service

The 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

StatusBodyDescription
200VerifiedAPIKeyEnvelope

The key behind this request

400ErrorResponse

The request did not authenticate with an API key

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

keyAPIKeyrequired

An API key without its secret. Personal prefixes start with whk_; organization prefixes start with who_.

effective_permissionsarray<string>required

What the key may do right now, after narrowing and the member's current roles.

Example

GET /api/v1/api_keys/verify
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/verify" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "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

DELETE/api/v1/me/api_keys/{id}Session cookieSelf-service

Revokes a key you minted. It stops working immediately. Revoking an already revoked key answers 204 again.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The API key's id, the part after whk_ or who_ in the token.

Response

Response codes

StatusBodyDescription
204

The key is revoked

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

No such key of yours

Example

DELETE /api/v1/me/api_keys/{id}
curl -X DELETE "$WITHHUMAN_URL/api/v1/me/api_keys/{id}" \
  -b "withhuman_session=$WITHHUMAN_SESSION"

List every API key in the organization

GET/api/v1/api_keysSession cookieRequires api_key.read

The oversight list for owners, admins, and auditors. Both personal and organization keys, newest first, with creator provenance. Never the secret.

Request

Parameters

ParameterTypeDescription
kindquery · enum

Omit to return both key kinds.

One of personal, organization

Response

Response codes

StatusBodyDescription
200APIKeysEnvelope

The organization's keys

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

keysarray<APIKey>required

Example

GET /api/v1/api_keys
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys" \
  -b "withhuman_session=$WITHHUMAN_SESSION"
200 response
{
  "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

GET/api/v1/api_keys/{id}Session cookieRequires api_key.read

Returns metadata, configured grants, effective organization-key grants, and policy availability. Never returns a secret.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The API key's id, the part after whk_ or who_ in the token.

Response

Response codes

StatusBodyDescription
200APIKey

Key metadata

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

grantsarray<Grant>required

Current organization-key grants projected from RBAC permission policies. Empty for personal keys.

On detail responses, currently allowed organization-key grants.

usablebooleanrequired

Whether the key is active and not blocked by organization policy or status.

One of organization_inactive, api_keys_disabled

iduuidrequired
prefixstringrequired
kindenumrequired

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.

namestringrequired
permissionsarray<string>required

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.

assurance_at_issuestringrequired

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.

statusenumrequired

One of active, expired, revoked

created_atdate-timerequired
expires_atdate-timerequired

null when the key lives until revoked.

last_used_atdate-timerequired
revoked_atdate-timerequired

One of manual, membership_deprovisioned

Example

GET /api/v1/api_keys/{id}
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/{id}" \
  -b "withhuman_session=$WITHHUMAN_SESSION"
200 response
{
  "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

DELETE/api/v1/api_keys/{id}Session cookieRequires api_key.revoke

Revokes anyone's key. It stops working immediately and the audit log records who revoked it.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The API key's id, the part after whk_ or who_ in the token.

Response

Response codes

StatusBodyDescription
204

The key is revoked

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

No such key

Example

DELETE /api/v1/api_keys/{id}
curl -X DELETE "$WITHHUMAN_URL/api/v1/api_keys/{id}" \
  -b "withhuman_session=$WITHHUMAN_SESSION"

Create an organization API keyHosted edition

POST/api/v1/api_keysSession cookieRequires api_key.organization.issue

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

ParameterTypeDescription
Idempotency-Keyrequiredheader · 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

namestringrequired

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.

expires_atdate-time

Response

Response codes

StatusBodyDescription
200OrganizationAPIKeyCreated

Already created. secret_available is false; the secret cannot be recovered.

201OrganizationAPIKeyCreated

Created, including the one-time secret. Cache-Control is no-store.

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Idempotency key reused for different intent

Response body200

secret_availablebooleanrequired
tokenstring

Returned only in the first creation response.

grantsarray<Grant>required

Current organization-key grants projected from RBAC permission policies. Empty for personal keys.

On detail responses, currently allowed organization-key grants.

usablebooleanrequired

Whether the key is active and not blocked by organization policy or status.

One of organization_inactive, api_keys_disabled

iduuidrequired
prefixstringrequired
kindenumrequired

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.

namestringrequired
permissionsarray<string>required

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.

assurance_at_issuestringrequired

The assurance of the session that minted the key (strong, single_factor), presented as the key's own when it decides.

statusenumrequired

One of active, expired, revoked

created_atdate-timerequired
expires_atdate-timerequired

null when the key lives until revoked.

last_used_atdate-timerequired
revoked_atdate-timerequired

One of manual, membership_deprovisioned

Example

POST /api/v1/api_keys
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"
}'
200 response
{
  "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

GET/api/v1/api_keys/optionsSession cookieRequires api_key.organization.issue

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

StatusBodyDescription
200OrganizationAPIKeyOptions

Available creation choices

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

max_ttlstringrequired

Maximum lifetime as a duration. 0s means no cap.

Example

GET /api/v1/api_keys/options
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/options" \
  -b "withhuman_session=$WITHHUMAN_SESSION"
200 response
{
  "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

GET/api/v1/api_keys/{id}/permission_policiesSession cookieSelf-service

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

ParameterTypeDescription
idrequiredpath · uuid

Response

Response codes

StatusBodyDescription
200PermissionPoliciesPage

Policy operation completed

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

namestringrequired
can_createbooleanrequired
is_ownerbooleanrequired

Example

GET /api/v1/api_keys/{id}/permission_policies
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies" \
  -b "withhuman_session=$WITHHUMAN_SESSION"
200 response
{
  "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

POST/api/v1/api_keys/{id}/permission_policiesSession cookieRequires permission_policy.write

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

ParameterTypeDescription
idrequiredpath · uuid
Idempotency-Keyrequiredheader · string

Request body

scope_kindenumrequired

One of organization, team, agent

resource_idsarray<string>required

Empty for organization scope; otherwise the selected team IDs or agent slugs.

permissionsarray<string>required

Response

Response codes

StatusBodyDescription
201PermissionPolicy

Policy operation completed

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body201

scope_kindenumrequired

One of organization, team, agent

resource_idsarray<string>required

Empty for organization scope; otherwise the selected team IDs or agent slugs.

permissionsarray<string>required
iduuidrequired
revisionint64required
sourceenumrequired

One of manual, directory

can_editbooleanrequired

Example

POST /api/v1/api_keys/{id}/permission_policies
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"
  ]
}'
201 response
{
  "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

GET/api/v1/api_keys/{id}/permission_policies/{policy_id}Session cookieSelf-service

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

ParameterTypeDescription
idrequiredpath · uuid
policy_idrequiredpath · uuid

Response

Response codes

StatusBodyDescription
200PermissionPolicy

Policy operation completed

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

scope_kindenumrequired

One of organization, team, agent

resource_idsarray<string>required

Empty for organization scope; otherwise the selected team IDs or agent slugs.

permissionsarray<string>required
iduuidrequired
revisionint64required
sourceenumrequired

One of manual, directory

can_editbooleanrequired

Example

GET /api/v1/api_keys/{id}/permission_policies/{policy_id}
curl -X GET "$WITHHUMAN_URL/api/v1/api_keys/{id}/permission_policies/{policy_id}" \
  -b "withhuman_session=$WITHHUMAN_SESSION"
200 response
{
  "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

PUT/api/v1/api_keys/{id}/permission_policies/{policy_id}Session cookieRequires permission_policy.write

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

ParameterTypeDescription
idrequiredpath · uuid
policy_idrequiredpath · uuid
Idempotency-Keyrequiredheader · string

Request body

scope_kindenumrequired

One of organization, team, agent

resource_idsarray<string>required

Empty for organization scope; otherwise the selected team IDs or agent slugs.

permissionsarray<string>required
revisionint64required

Required when updating an existing policy.

Response

Response codes

StatusBodyDescription
200PermissionPolicy

Policy operation completed

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

scope_kindenumrequired

One of organization, team, agent

resource_idsarray<string>required

Empty for organization scope; otherwise the selected team IDs or agent slugs.

permissionsarray<string>required
iduuidrequired
revisionint64required
sourceenumrequired

One of manual, directory

can_editbooleanrequired

Example

PUT /api/v1/api_keys/{id}/permission_policies/{policy_id}
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
}'
200 response
{
  "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

DELETE/api/v1/api_keys/{id}/permission_policies/{policy_id}Session cookieRequires permission_policy.write

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

ParameterTypeDescription
idrequiredpath · uuid
policy_idrequiredpath · uuid
Idempotency-Keyrequiredheader · string
revisionrequiredquery · integer

Response

Response codes

StatusBodyDescription
204

Policy operation completed

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Example

DELETE /api/v1/api_keys/{id}/permission_policies/{policy_id}
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"