Management API: API keys

Last updated 2 November 2026

View .md

Keys of the account's members, people and Agents. The overview covers what every operation shares: authentication, roles, errors, pagination, idempotency and If-Match.

List your keys, or every key of the account for an owner or admin

GET /v1/api-keys · CLI: tonbo api-key list

Needs api_keys.own, which owner, admin and member hold. A narrowed key may not.

Parameters

NameInTypeRequiredDescription
cursorquerystringnoOpaque cursor tied to the original query shape. At least 1 characters.
limitqueryintegernoThe most items one page holds, 1 to 200; 50 when omitted. A page may hold fewer; read on with next_cursor until it is null. Default 50. 1 to 200.

Response

StatusAnswer
200Live keys
FieldTypeRequiredDescription
dataarray of ApiKeyyes
next_cursorstring or nullyesOpaque cursor of the next page; null on the last page.
HeaderStatusDescription
WWW-Authenticate401Authentication scheme required by this API.
Retry-After429Seconds before the client should retry.
Example 200 body
{
  "data": [
    {
      "id": "3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
      "name": "<name>",
      "member": "agent.3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
      "member_kind": "user",
      "last4": "<last4>",
      "read_only": false,
      "buckets": [
        "<buckets>"
      ],
      "databases": [
        "<databases>"
      ],
      "database_prefixes": [
        "<database_prefixes>"
      ],
      "streams": [
        "<streams>"
      ],
      "stream_prefixes": [
        "<stream_prefixes>"
      ],
      "expires_at": "2026-11-02T09:30:00.000Z",
      "last_used_at": "2026-11-02T09:30:00.000Z",
      "created_at": "2026-11-02T09:30:00.000Z"
    }
  ],
  "next_cursor": "<next_cursor>"
}

Errors

StatusCodeWhenSend againWhat to do
401exchange_requiredThe key acts as an Agent, and an Agent’s key is never sent itself.NoExchange the key for a token at the endpoint the answer’s token_endpoint names, and send the token as Authorization: Bearer. (more)
401unauthenticatedThe request carries no key or token, or one that is invalid, expired or revoked.NoSend a valid key, or a token that has not expired, as Authorization: Bearer. (more)
403forbiddenThe key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.NoUse a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
422validation_errorA parameter, header or body field breaks its rule; errors names each field.NoCorrect the fields errors names; the operation’s reference gives each one’s rule. (more)
429rate_limitedThe key or the account sent more requests than its rate allows.After Retry-AfterWait for the seconds Retry-After names, then send the request again; spread requests out if it recurs. (more)

Retries

  • A read: sending it again changes nothing.
  • 429 carry Retry-After: wait that many seconds, then send the same request again.
Request
curl -sS "https://api.tonbo.dev/v1/api-keys" \
  -H "Authorization: Bearer $TONBO_API_KEY"

Create a key; its secret is in this answer only

POST /v1/api-keys · CLI: tonbo api-key create

Needs api_keys.own, which owner, admin and member hold. A narrowed key may not.

A personal key acts as you; an Agent key (member: agent.<agent id>), which owners and admins create, acts as the Agent, whose role may not exceed yours. read_only, and either buckets or any of databases, database_prefixes, streams and stream_prefixes, narrow the key for its whole life: a different narrowing takes a new key. An access token never creates a key, and neither does a narrowed key.

Request body

application/json, required. Unknown fields are refused.

FieldTypeRequiredDescription
namestringyesA name to tell the key apart, 1 to 80 characters once spaces are trimmed; unique, ignoring case, among the member's live keys, so a second live key with the name answers 409. 1 to 80 characters.
memberstringnoOmit for your own personal key; agent.<agent id> for an Agent key. Matches ^[a-z0-9._-]{1,64}$.
read_onlybooleannoNarrow the key to read-only actions, for its whole life. Default false.
bucketsarray of stringnoNarrow the key to these registered buckets of the account, for its whole life. Never with databases, database_prefixes, streams or stream_prefixes. At most 20 items. No duplicates.
databasesarray of stringnoNarrow the key to these databases, for its whole life; a name need not exist yet. Never with buckets. At most 20 items. No duplicates.
database_prefixesarray of stringnoNarrow the key to the databases whose name starts with one of these, for its whole life. Never with buckets. At most 20 items. No duplicates.
streamsarray of stringnoNarrow the key to these raw streams, by the name the streams API shows, for its whole life; a name need not exist yet. Never with buckets. A key narrowed to both databases and streams reaches both. At most 20 items. No duplicates.
stream_prefixesarray of stringnoNarrow the key to the raw streams whose name starts with one of these, for its whole life; each at most 83 bytes, the longest stream name. Never with buckets. At most 20 items. No duplicates.
expires_inone of "15_days", "1_month", "6_months", "1_year" or "never"noHow long the key lives from now; it never expires when omitted. Default "never".

Response

StatusAnswer
201The key and its secret
FieldTypeRequiredDescription
dataApiKeyWithSecretyes
HeaderStatusDescription
WWW-Authenticate401Authentication scheme required by this API.
Retry-After429Seconds before the client should retry.
Example 201 body
{
  "data": {
    "id": "3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
    "name": "<name>",
    "member": "agent.3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
    "member_kind": "user",
    "last4": "<last4>",
    "read_only": false,
    "buckets": [
      "<buckets>"
    ],
    "databases": [
      "<databases>"
    ],
    "database_prefixes": [
      "<database_prefixes>"
    ],
    "streams": [
      "<streams>"
    ],
    "stream_prefixes": [
      "<stream_prefixes>"
    ],
    "expires_at": "2026-11-02T09:30:00.000Z",
    "last_used_at": "2026-11-02T09:30:00.000Z",
    "created_at": "2026-11-02T09:30:00.000Z",
    "key": "<key>"
  }
}

Errors

StatusCodeWhenSend againWhat to do
401exchange_requiredThe key acts as an Agent, and an Agent’s key is never sent itself.NoExchange the key for a token at the endpoint the answer’s token_endpoint names, and send the token as Authorization: Bearer. (more)
401unauthenticatedThe request carries no key or token, or one that is invalid, expired or revoked.NoSend a valid key, or a token that has not expired, as Authorization: Bearer. (more)
403forbiddenThe key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.NoUse a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
404not_foundNo live resource of the key’s account has that name or id, or the key is narrowed away from it.NoCheck the name, and that the key belongs to the account that holds it; list the resources to see what exists. (more)
409conflictThe name is held by another live resource of the account, the Idempotency-Key already created another resource or one since deleted, or the resource’s current state does not allow the change. detail says which, and errors names the field.NoPick another name or a new Idempotency-Key, or read the resource again and act on its current state. (more)
422validation_errorA parameter, header or body field breaks its rule; errors names each field.NoCorrect the fields errors names; the operation’s reference gives each one’s rule. (more)
429rate_limitedThe key or the account sent more requests than its rate allows.After Retry-AfterWait for the seconds Retry-After names, then send the request again; spread requests out if it recurs. (more)

Retries

  • No Idempotency-Key: the secret is never stored, so a replay cannot return it; a live key name is unique, so a blind retry answers 409 instead of creating a second key.
  • 429 carry Retry-After: wait that many seconds, then send the same request again.
Request
curl -sS "https://api.tonbo.dev/v1/api-keys" \
  -H "Authorization: Bearer $TONBO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"laptop"}'

Read one key

GET /v1/api-keys/{key_id} · CLI: tonbo api-key show

Needs api_keys.own, which owner, admin and member hold. A narrowed key may not.

Parameters

NameInTypeRequiredDescription
key_idpathstring (uuid)yesThe key's id, as GET /v1/api-keys lists it.

Response

StatusAnswer
200The key
FieldTypeRequiredDescription
dataApiKeyyes
HeaderStatusDescription
ETag200Current resource version for optional conditional updates.
WWW-Authenticate401Authentication scheme required by this API.
Retry-After429Seconds before the client should retry.
Example 200 body
{
  "data": {
    "id": "3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
    "name": "<name>",
    "member": "agent.3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
    "member_kind": "user",
    "last4": "<last4>",
    "read_only": false,
    "buckets": [
      "<buckets>"
    ],
    "databases": [
      "<databases>"
    ],
    "database_prefixes": [
      "<database_prefixes>"
    ],
    "streams": [
      "<streams>"
    ],
    "stream_prefixes": [
      "<stream_prefixes>"
    ],
    "expires_at": "2026-11-02T09:30:00.000Z",
    "last_used_at": "2026-11-02T09:30:00.000Z",
    "created_at": "2026-11-02T09:30:00.000Z"
  }
}

Errors

StatusCodeWhenSend againWhat to do
401exchange_requiredThe key acts as an Agent, and an Agent’s key is never sent itself.NoExchange the key for a token at the endpoint the answer’s token_endpoint names, and send the token as Authorization: Bearer. (more)
401unauthenticatedThe request carries no key or token, or one that is invalid, expired or revoked.NoSend a valid key, or a token that has not expired, as Authorization: Bearer. (more)
403forbiddenThe key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.NoUse a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
404not_foundNo live resource of the key’s account has that name or id, or the key is narrowed away from it.NoCheck the name, and that the key belongs to the account that holds it; list the resources to see what exists. (more)
429rate_limitedThe key or the account sent more requests than its rate allows.After Retry-AfterWait for the seconds Retry-After names, then send the request again; spread requests out if it recurs. (more)

Retries

  • A read: sending it again changes nothing.
  • 429 carry Retry-After: wait that many seconds, then send the same request again.
Request
curl -sS "https://api.tonbo.dev/v1/api-keys/<key_id>" \
  -H "Authorization: Bearer $TONBO_API_KEY"

Revoke a key and every token minted from it

DELETE /v1/api-keys/{key_id} · CLI: tonbo api-key revoke

Needs api_keys.own, which owner, admin and member hold. A narrowed key may not.

Your own key, or any key of the account for an owner or admin. A narrowed key may revoke itself (tonbo logout).

Parameters

NameInTypeRequiredDescription
key_idpathstring (uuid)yesThe key's id, as GET /v1/api-keys lists it.

Response

StatusAnswer
200The revocation
FieldTypeRequiredDescription
dataobjectyes
data.idstring (uuid)yesA UUID in lowercase hex with hyphens.
data.revoked_atstring (date-time)yesAn RFC 3339 time; answers give it in UTC.
HeaderStatusDescription
WWW-Authenticate401Authentication scheme required by this API.
Retry-After429Seconds before the client should retry.
Example 200 body
{
  "data": {
    "id": "3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
    "revoked_at": "2026-11-02T09:30:00.000Z"
  }
}

Errors

StatusCodeWhenSend againWhat to do
401exchange_requiredThe key acts as an Agent, and an Agent’s key is never sent itself.NoExchange the key for a token at the endpoint the answer’s token_endpoint names, and send the token as Authorization: Bearer. (more)
401unauthenticatedThe request carries no key or token, or one that is invalid, expired or revoked.NoSend a valid key, or a token that has not expired, as Authorization: Bearer. (more)
403forbiddenThe key’s role does not hold the capability the operation needs, the key is narrowed away from the resource, or the account already holds as many of the resource as it may.NoUse a key whose role holds the capability, or one that is not narrowed; delete what you no longer need, or ask for a higher limit. (more)
404not_foundNo live resource of the key’s account has that name or id, or the key is narrowed away from it.NoCheck the name, and that the key belongs to the account that holds it; list the resources to see what exists. (more)
429rate_limitedThe key or the account sent more requests than its rate allows.After Retry-AfterWait for the seconds Retry-After names, then send the request again; spread requests out if it recurs. (more)

Retries

  • It takes no Idempotency-Key; its description above says what sending it again does.
  • 429 carry Retry-After: wait that many seconds, then send the same request again.
Request
curl -sS -X DELETE "https://api.tonbo.dev/v1/api-keys/<key_id>" \
  -H "Authorization: Bearer $TONBO_API_KEY"

Objects

ApiKey

FieldTypeRequiredDescription
idstring (uuid)yesThe key's id, which GET and DELETE /v1/api-keys/{key_id} name.
namestringyesThe key's name, unique, ignoring case, among its member's live keys.
memberstringyesWho the key acts as, with that member's current role: a person's user id, or agent.<agent id> for an Agent key. Matches ^[a-z0-9._-]{1,64}$.
member_kindone of "user" or "agent"yesuser for a person's key, agent for an Agent key.
last4stringyesThe secret's last four characters, to tell keys apart; the secret itself is shown only when the key is created. 4 to 4 characters.
read_onlybooleanyesWhether the key is narrowed to read-only actions.
bucketsarray of stringyesThe buckets the key is narrowed to; empty when it is not narrowed by bucket.
databasesarray of stringyesThe database names the key is narrowed to. A key whose five narrowing lists are all empty reaches everything its member does; otherwise it reaches only what the lists name.
database_prefixesarray of stringyesThe database name prefixes the key is narrowed to.
streamsarray of stringyesThe stream names the key is narrowed to, without s..
stream_prefixesarray of stringyesThe stream name prefixes the key is narrowed to.
expires_atstring (date-time) or nullyesWhen the key stops working; null when it never expires.
last_used_atstring (date-time) or nullyesRecorded at most once a minute.
created_atstring (date-time)yesWhen the key was created.
Example ApiKey
{
  "id": "3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
  "name": "<name>",
  "member": "agent.3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
  "member_kind": "user",
  "last4": "<last4>",
  "read_only": false,
  "buckets": [
    "<buckets>"
  ],
  "databases": [
    "<databases>"
  ],
  "database_prefixes": [
    "<database_prefixes>"
  ],
  "streams": [
    "<streams>"
  ],
  "stream_prefixes": [
    "<stream_prefixes>"
  ],
  "expires_at": "2026-11-02T09:30:00.000Z",
  "last_used_at": "2026-11-02T09:30:00.000Z",
  "created_at": "2026-11-02T09:30:00.000Z"
}

ApiKeyWithSecret

FieldTypeRequiredDescription
idstring (uuid)yesThe key's id, which GET and DELETE /v1/api-keys/{key_id} name.
namestringyesThe key's name, unique, ignoring case, among its member's live keys.
memberstringyesWho the key acts as, with that member's current role: a person's user id, or agent.<agent id> for an Agent key. Matches ^[a-z0-9._-]{1,64}$.
member_kindone of "user" or "agent"yesuser for a person's key, agent for an Agent key.
last4stringyesThe secret's last four characters, to tell keys apart; the secret itself is shown only when the key is created. 4 to 4 characters.
read_onlybooleanyesWhether the key is narrowed to read-only actions.
bucketsarray of stringyesThe buckets the key is narrowed to; empty when it is not narrowed by bucket.
databasesarray of stringyesThe database names the key is narrowed to. A key whose five narrowing lists are all empty reaches everything its member does; otherwise it reaches only what the lists name.
database_prefixesarray of stringyesThe database name prefixes the key is narrowed to.
streamsarray of stringyesThe stream names the key is narrowed to, without s..
stream_prefixesarray of stringyesThe stream name prefixes the key is narrowed to.
expires_atstring (date-time) or nullyesWhen the key stops working; null when it never expires.
last_used_atstring (date-time) or nullyesRecorded at most once a minute.
created_atstring (date-time)yesWhen the key was created.
keystringyesThe secret, shown once. tbo_ followed by 50 base-58 characters, the last six a checksum. Matches ^tbo_[1-9A-HJ-NP-Za-km-z]{50}$.
Example ApiKeyWithSecret
{
  "id": "3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
  "name": "<name>",
  "member": "agent.3f1c2a9e-5b7d-4c8e-9f10-2a3b4c5d6e7f",
  "member_kind": "user",
  "last4": "<last4>",
  "read_only": false,
  "buckets": [
    "<buckets>"
  ],
  "databases": [
    "<databases>"
  ],
  "database_prefixes": [
    "<database_prefixes>"
  ],
  "streams": [
    "<streams>"
  ],
  "stream_prefixes": [
    "<stream_prefixes>"
  ],
  "expires_at": "2026-11-02T09:30:00.000Z",
  "last_used_at": "2026-11-02T09:30:00.000Z",
  "created_at": "2026-11-02T09:30:00.000Z",
  "key": "<key>"
}