API keys
API keys are the credentials everything else authenticates with. This page documents managing them over the API itself: the key object, creation from a role or an explicit scope list, listing with last-used metadata, and revocation. How authentication works, scopes, roles, rotation, is covered in Authentication.
Shared conventions, including pagination, the Idempotency-Key header, and the error envelope, are defined in the API overview. Error codes are catalogued in Errors.
The keys:read and keys:write scopes are granted only through the admin role. The first admin key for a tenant is created in the Fibric console during onboarding; everything after that can be automated through these endpoints. Key management, like every write, is recorded in the receipt ledger.
The API key object
The object never contains the secret after creation; only the display hint survives.
Unique identifier, prefixed key_. This is the id you list, retrieve, and revoke by; it is not the secret.
Always api_key.
Human label, unique among the tenant's active keys, for example ingest-gateway-2026-07. Name keys after the workload that holds them.
live or test. Determines the secret's prefix (sk_live_ / sk_test_) and which data partition the key reaches. See key anatomy.
The role preset the key was created from: read_only, ingest, operate, or admin. null when the key was created from an explicit scopes list.
The expanded scope set, stored at creation. A later change to a role's definition never changes an existing key's scopes.
Workspace pin. null means the key sees the whole tenant. See workspace scoping.
Display form of the secret, prefix plus last four characters, for example sk_live_…a2c9. For matching a key you hold to its record.
active or revoked. Revocation is permanent; there is no re-activation.
RFC 3339 timestamp of the most recent authenticated request, accurate to within a few minutes. null if the key has never been used. The signal that drives safe rotation.
RFC 3339 timestamp of creation.
RFC 3339 timestamp of revocation. null while active.
{
"id": "key_4e12ab",
"object": "api_key",
"name": "ingest-gateway",
"mode": "live",
"role": "ingest",
"scopes": ["events:write"],
"workspace_id": null,
"hint": "sk_live_…41f7",
"status": "active",
"last_used_at": "2026-07-02T15:11:02Z",
"created_at": "2026-05-20T09:00:00Z",
"revoked_at": null
}
Create a key
keys:writeMints a new key. Provide either a role or an explicit scopes list, not both. The response is the only place the full secret ever appears; store it immediately.
Human label, unique among the tenant's active keys. 3–60 characters.
One of read_only, ingest, operate, admin. Expanded to scopes at creation; see roles.
Explicit scope list, for callers that need a set no role provides. Mutually exclusive with role.
live or test. Defaults to live.
Pin the key to one workspace. Defaults to null (whole tenant).
curl -X POST https://api.fibric.io/v1/keys \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: key-create-ingest-gateway" \
-d '{"name": "ingest-gateway", "role": "ingest"}'
{
"id": "key_4e12ab",
"object": "api_key",
"name": "ingest-gateway",
"mode": "live",
"role": "ingest",
"scopes": ["events:write"],
"workspace_id": null,
"hint": "sk_live_…41f7",
"secret": "sk_live_8d1c5e2f9a0b7c3d41f7",
"status": "active",
"last_used_at": null,
"created_at": "2026-07-02T15:20:00Z",
"revoked_at": null
}
The secret field is present only on this creation response. Every later read returns the hint only. If the secret is not captured here, revoke the key and mint another.
Error cases:
| Status | Code | When |
|---|---|---|
400 | missing_parameter | name is absent, or neither role nor scopes is provided. |
400 | invalid_parameter | Both role and scopes are provided, role is not a known preset, or a scope name is unknown. |
403 | insufficient_scope | The calling key lacks keys:write. |
409 | state_conflict | An active key with this name already exists. |
List keys
keys:readReturns the tenant's keys, newest first, cursor-paginated. Revoked keys remain listed for audit; filter by status to hide them.
Filter by active or revoked. Omit to return all.
Filter by live or test.
Page size, 1–100. Defaults to 20.
Pagination cursor from a previous response's next_cursor.
curl "https://api.fibric.io/v1/keys?status=active" \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY"
{
"object": "list",
"data": [
{
"id": "key_4e12ab",
"object": "api_key",
"name": "ingest-gateway",
"mode": "live",
"role": "ingest",
"hint": "sk_live_…41f7",
"status": "active",
"last_used_at": "2026-07-02T15:11:02Z",
"created_at": "2026-05-20T09:00:00Z"
},
{
"id": "key_1b09cd",
"object": "api_key",
"name": "ops-dashboard",
"mode": "live",
"role": "read_only",
"hint": "sk_live_…9c02",
"status": "active",
"last_used_at": "2026-07-02T15:19:47Z",
"created_at": "2026-04-02T11:30:00Z"
}
],
"has_more": false,
"next_cursor": null
}
Retrieve a key
keys:readReturns the full key object, without the secret. The most common use is polling last_used_at during a rotation.
The key id, for example key_4e12ab.
curl https://api.fibric.io/v1/keys/key_4e12ab \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY"
Error cases:
| Status | Code | When |
|---|---|---|
404 | not_found | No key with this id exists for the authenticated tenant. |
Revoke a key
keys:writeRevokes a key immediately and permanently. In-flight requests already authenticated complete; the next request with the revoked secret fails with 401 key_revoked. The record remains readable with status: "revoked" for audit. Revoking an already-revoked key is a no-op and returns the record unchanged.
The key id to revoke.
curl -X DELETE https://api.fibric.io/v1/keys/key_4e12ab \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY"
{
"id": "key_4e12ab",
"object": "api_key",
"name": "ingest-gateway",
"status": "revoked",
"revoked_at": "2026-07-02T16:00:00Z"
}
Error cases:
| Status | Code | When |
|---|---|---|
403 | insufficient_scope | The calling key lacks keys:write. |
404 | not_found | No key with this id exists for the authenticated tenant. |
409 | state_conflict | The target is the calling key itself and it is the tenant's only active admin key. A tenant cannot lock itself out; mint a replacement first. |
Best practices
- One key per workload. Name it after the workload. When something misbehaves,
last_used_atand the name tell you exactly which deployment to look at, and revocation takes down one integration, not five. - Smallest role that works. An ingest gateway needs
ingest, notadmin. See least-privilege roles. - Rotate on a schedule and on suspicion. The overlap-cut-revoke procedure is zero-downtime; there is no reason not to. See rotation.
- Audit quarterly. List active keys and revoke any whose
last_used_athas gone stale. An unused active key is pure risk. - Keep admin keys out of workloads. Reserve
adminfor provisioning automation and break-glass. Nothing that serves traffic needskeys:write.