API reference

API keys

  • 1 endpoint

An API key belongs to one space (spaces): the organization's shared space, where it acts as an admin of the organization, or a member's personal space, where it acts as that member. Its mode (test or live) is the space's.

List API keys#

GET /api-keys

A page of the keys of the caller's space (a member's own keys; the shared keys for the team), newest first, or with includeMembers=true every key of the organization in the request's mode. A member needs the members.apiKeys policy (403 policy_disabled).

Auth
X-API-Key: any keyA member's key needs the members.apiKeys policy
On-Behalf-Of
Honored: acts in the member's space
Idempotency-Key
Ignored
Success
200
Request

request.sh

curl https://api.qbitflow.app/v2/api-keys \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: a page of ApiKey ({ items, hasMore, nextCursor? })

Query parameters

  • limitintegerOptional

    Page size: 20 when absent or ≤ 0, at most 100 (a larger one is clamped, not refused)

  • cursorstringOptional

    The previous page's nextCursor, verbatim; omit for the first page

    max=200

  • includeMembersbooleanOptional

    With true: every key of the organization in the request's mode, its members' included (userUuid names the member), for an owner or admin to find a key to revoke (403 forbidden for anyone else; 400 validation_failed from a member's space). Default false: the request's space's keys

Response

A page: { "items": ApiKey[], "hasMore": …, "nextCursor"?: … }. Pass nextCursor back as cursor for the next page; it is absent when hasMore is false.

9 fields of each ApiKey
  • uuidstring

    Its only id (a UUIDv7)

  • namestring

    Name of the API key

  • testboolean

    Whether this is test data (testnets) or live data

  • userUuidstringOptional

    Member the resource belongs to; omitted for the organization's own resources

    Only for the resource's owner

  • createdByUserUuidstringOptional

    Who created the key (omitted once that user is deleted). A shared-space key acts for them in the audit trail, and outlives them

  • rolestring

    Role is the most the key acts as, fixed at its creation: admin for the organization's keys, the member's role then for a member's (user). A member's key acts with the lower of it and the member's role now: a demotion narrows it, a promotion never widens it (a member made admin keeps a member's key, which can't act On-Behalf-Of: they create a new key for their new role)

  • createdAtstring

    Timestamp when the API key was created

  • expiresAtstringOptional

    When the API key expires; absent if it never expires

  • lastUsedAtstringOptional

    When a request last authenticated with the key, within the hour (recorded at most once an hour); absent if it never was

Errors

  • 403policy_disabled

    a member doing what their organization's policy doesn't allow them, reads of what the policy governs included

Edge cases

The contract's rules for these routes: Authentication & roles · Authentication with a key · List — GET /api-keys · Status-code summary.

Read all 4

Authentication & roles

  • Create and delete are dashboard-only: an API key there → 404, so keys never mint or revoke keys. Both need a recent re-authentication (403 reauth_required).
  • A qbf.cash session → 404.

Authentication with a key

  • A key whose live/test label was edited (it no longer matches its space) → 401. An expired, revoked or malformed key → 401.
  • Keys in the format v1 issued (sk_<digits>_<live|test>_<secret>) don't authenticate: 401 unauthorized, like any key whose id part isn't a uuid (or is the nil uuid). They were deleted at the launch: GET /api-keys lists only keys created in v2. A key with its uuid before its mode (sk_<uuid>_<live|test>_<secret>, the format issued until the mode moved first) → 401 unauthorized too: create a new key. A member's key stops authenticating when the member is removed from that mode (401).
  • A member's key acts as the member, in their space: it sees their products, not the organization's (and the reverse, without On-Behalf-Of).

List — GET /api-keys

  • A page of keys, newest first (createdAt, then uuid), in the list envelope (limit 20 by default, at most 100; cursor = the previous page's nextCursor; a cursor that isn't one → 400 validation_failed on cursor).
  • Without includeMembers (or false): the keys of the request's space. The team (owner, admins) sees the organization's keys, whoever created them; a member sees only their own; On-Behalf-Of a member lists the member's. Another organization's keys, and the other mode's, never appear.
  • ?includeMembers=true: every key of the organization in the request's mode, members' keys included (a member's key has userUuid, the member; the organization's keys have none), for an owner or admin to find a key to revoke. Below admin in the space (a member, a member's key, an organization key acting On-Behalf-Of a member, an owner switched into a member's space) → 403 forbidden. Switch mode for the other mode's keys.
  • ApiKey never carries the hashed secret.

Status-code summary

  • 401 unauthenticated, or an invalid, expired, revoked or relabelled key.
  • 403: includeMembers below admin in the space; creating a key as a member without the members.apiKeys policy (policy_disabled), or for a member from the team (forbidden); revoking a key of the organization the caller doesn't manage; reauth_required.
  • 404 another organization's key or an unknown uuid, and dashboard-only routes with a key.
  • 400 validation failure. 200 list, 201 create, 204 revoke.

The codes named here

  • 400validation_failed

    path/query/body failed binding or validation, or a business rule about one input (a field named in errors)

  • 401unauthorized

    missing / invalid JWT or API key, an ended login

  • 403forbidden

    authenticated but not allowed (role, peer resource)

  • 403policy_disabled

    a member doing what their organization's policy doesn't allow them, reads of what the policy governs included