Skip to content

Enterprise API Keys ​

Enterprise API keys (chb_sk_*) provide account-scoped bearer authentication for service-to-service integrations and automated pipelines.

Base path: /api/v1/accounts/{accountId}/api-keys

Authentication: JWT Bearer token


List API Keys ​

GET /accounts/{accountId}/api-keys

Returns all API keys for the account. The raw key value is never returned in list responses.

Request ​

Path ParameterDescription
accountIdAccount UUID

No query or body parameters.

Response ​

json
{
  "data": [
    {
      "id": "uuid",
      "name": "Production Pipeline Key",
      "keyPrefix": "chb_sk_xxxx",
      "lastFour": "abcd",
      "scopes": ["contexts:read", "agents:read"],
      "status": "active",
      "workspaceId": null,
      "expiresAt": "2026-07-12T10:00:00.000Z",
      "lastUsedAt": "2026-04-10T14:22:00.000Z",
      "createdAt": "2026-04-13T10:00:00.000Z"
    }
  ]
}

Code Example ​

bash
curl "https://api.chainabit.com/api/v1/accounts/$ACCOUNT_ID/api-keys" \
  -H "Authorization: Bearer $TOKEN"
javascript
const response = await fetch(
  `${BASE_URL}/accounts/${accountId}/api-keys`,
  { headers: { Authorization: `Bearer ${TOKEN}` } }
);
const { data } = await response.json();
python
import httpx
result = httpx.get(
    f"{BASE_URL}/accounts/{account_id}/api-keys",
    headers={"Authorization": f"Bearer {token}"},
).json()

Create API Key ​

POST /accounts/{accountId}/api-keys

Creates a new API key. The raw key value is only present in this response — it cannot be retrieved later. Store it immediately.

Request ​

Path ParameterDescription
accountIdAccount UUID

Request body:

FieldTypeRequiredDescription
namestringYesHuman-readable label
scopesstring[]YesPermission scopes
workspaceIduuidNoRestrict key to a specific workspace
expiresInDaysintegerNoDays until expiry (1–365); defaults to 90 when omitted. Every key expires.

Available scopes:

ScopeAccess grantedCan be granted at creation
contexts:readRead knowledge contexts, semantic searchYes
contexts:writeCreate and update knowledge contextsNo — requires review
agents:readRead agent definitions and instancesYes
agents:executeExecute agent tools and sessionsNo — requires review
analytics:readRead analytics and audit dataYes
members:readRead account and workspace membersYes

Scopes that require review cannot be granted yet. If scopes contains one, the whole request is refused with 403 and error code enterprise_api_key_scope_review_required, and no key is created. The error message names the refused scopes. See Current limitations.

Response ​

json
{
  "data": {
    "id": "uuid",
    "name": "Production Pipeline Key",
    "key": "chb_sk_AbCdEfGhIjKlMnOpQrStUvWxYz01234567890AbCdEfG",
    "keyPrefix": "chb_sk_AbCd",
    "lastFour": "fGhI",
    "scopes": ["contexts:read", "agents:read"],
    "expiresAt": "2026-07-12T10:00:00.000Z",
    "createdAt": "2026-04-13T10:00:00.000Z"
  }
}

Code Example ​

bash
curl -X POST "https://api.chainabit.com/api/v1/accounts/$ACCOUNT_ID/api-keys" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Pipeline Key",
    "scopes": ["contexts:read", "agents:read"],
    "expiresInDays": 90
  }'
javascript
const response = await fetch(
  `${BASE_URL}/accounts/${accountId}/api-keys`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Production Pipeline Key',
      scopes: ['contexts:read', 'agents:read'],
      expiresInDays: 90,
    }),
  }
);
const { data } = await response.json();
// data.key is the raw key — store it now
python
import httpx
result = httpx.post(
    f"{BASE_URL}/accounts/{account_id}/api-keys",
    json={
        "name": "Production Pipeline Key",
        "scopes": ["contexts:read", "agents:read"],
        "expiresInDays": 90,
    },
    headers={"Authorization": f"Bearer {token}"},
).json()
# result['data']['key'] — store this immediately

Revoke API Key ​

DELETE /accounts/{accountId}/api-keys/{id}

Immediately revokes the key. Revoked keys return 401 on any subsequent request.

Request ​

Path ParameterDescription
accountIdAccount UUID
idAPI key UUID

Response ​

json
{ "data": { "revoked": true, "id": "uuid" } }

Code Example ​

bash
curl -X DELETE "https://api.chainabit.com/api/v1/accounts/$ACCOUNT_ID/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $TOKEN"
javascript
await fetch(
  `${BASE_URL}/accounts/${accountId}/api-keys/${keyId}`,
  { method: 'DELETE', headers: { Authorization: `Bearer ${TOKEN}` } }
);
python
httpx.delete(
    f"{BASE_URL}/accounts/{account_id}/api-keys/{key_id}",
    headers={"Authorization": f"Bearer {token}"},
)

Using an API Key ​

Once created, use the raw key directly as a bearer token on supported endpoints:

http
Authorization: Bearer chb_sk_<your-key>

Every request is checked again, with nothing cached between requests:

  • The key must exist, be active, and be unexpired. Otherwise the request returns 401.
  • The key's account must be active. If the account is suspended, closed, approved for deletion, or deleted, or has a deletion request that is pending, under review, or approved, the request returns 403 with error code enterprise_account_not_active. This applies to every key of the account.
  • A key restricted to a workspace (workspaceId) returns 403 with error code enterprise_workspace_access_denied once that workspace is deactivated or no longer belongs to the account.

A change to the account's or workspace's status applies from the key's next request.


Errors ​

StatusCodeDescription
400BAD_REQUESTWorkspace not found in this account
403FORBIDDENCaller is not an account owner or admin
403enterprise_api_key_scope_review_requiredCreate only: scopes contains a scope that requires review
403enterprise_account_not_activeRequest made with a key whose account is not active or has a deletion request
403enterprise_workspace_access_deniedRequest made with a workspace-restricted key whose workspace is no longer active
404NOT_FOUNDKey not found or already revoked

Current limitations ​

  • Review-required scopes are unavailable. contexts:write and agents:execute need a review step that does not exist yet, so a new key cannot be granted them. Keys created before this restriction keep the scopes they were granted.
  • A deletion request blocks every key. While the account has a pending, in-review, or approved deletion request, all of its keys are refused, not only keys created by the member who requested deletion.

Built with purpose.