Tenants API
A tenant is the unit of isolation in Fibric: every envelope, plan, action, and receipt is stamped with a tenant_id and, where one exists, a reseller_id above it. This page documents reading the tenant you authenticate as, managing workspaces within it, and managing members. The isolation model itself is described in Tenancy & isolation.
Shared conventions, including authentication, pagination, the Idempotency-Key header, and the error envelope, are defined in the API overview. Error codes are catalogued in Errors.
The reseller hierarchy
Three levels exist, and the API exposes exactly one of them to a key:
- Reseller. An organization that operates Fibric for its own customers. Identified by
reseller_id. A tenant provisioned directly by Fibric hasreseller_id: null. - Tenant. One customer organization, prefixed
t_. The wall: keys, data, quotas, connectors, operators, and receipts are all tenant-scoped. - Workspace. An optional partition inside a tenant, prefixed
ws_, for separating brands, regions, or environments that share one contract. Objects carryworkspace_id; keys may be pinned to one workspace.
There is no reseller-level API surface in v0.9: a reseller administers each of its tenants with that tenant's own keys, and no key spans tenants. The reseller_id on your objects is informational, stamped for the audit trail, and appears on every envelope and receipt.
Isolation guarantees
The guarantees every endpoint honors, stated once here and assumed everywhere else in this reference:
| Guarantee | Mechanism |
|---|---|
| A key reads and writes exactly one tenant. | Tenancy is derived from the key on every request, never from the body. See Authentication. |
| Cross-tenant existence is never disclosed. | Another tenant's id reads as 404 not_found, indistinguishable from an id that never existed. |
| A body cannot widen the wall. | A mismatched tenant_id, reseller_id, or workspace_id in a body is rejected with 403 tenant_mismatch. |
| Every stored row is stamped. | reseller_id and tenant_id are columns on every row, enforced by row-level security in the store, not by application code alone. |
| Quotas and rate limits are per tenant. | One tenant's burst cannot consume another's budget. See Rate limits & quotas. |
The tenant object
Unique identifier, prefixed t_. The value stamped as tenant_id on every object the tenant owns.
Always tenant.
Display name of the organization.
URL-safe identifier, unique across the platform, for example acme-fulfillment. Immutable after provisioning.
The reseller this tenant belongs to. null means Fibric-direct. Immutable.
The commercial plan, for example early_access or team. Plan changes are made with your Fibric contact, not over the API.
The tenant's workspaces, each with id, name, and created_at. Empty when the tenant does not partition.
RFC 3339 timestamp of provisioning.
{
"id": "t_8f2ac901",
"object": "tenant",
"name": "Acme Fulfillment",
"slug": "acme-fulfillment",
"reseller_id": null,
"plan": "early_access",
"workspaces": [
{ "id": "ws_2d81f0", "name": "us-store", "created_at": "2026-05-01T10:00:00Z" },
{ "id": "ws_9a44c2", "name": "eu-store", "created_at": "2026-06-12T09:30:00Z" }
],
"created_at": "2026-04-01T12:00:00Z"
}
Retrieve the tenant
tenants:readReturns the tenant the calling key belongs to. The route is singular by design: there is no /tenants collection to list, because no key can see more than one.
curl https://api.fibric.io/v1/tenant \
-H "Authorization: Bearer $FIBRIC_KEY"
The response is the tenant object above. This endpoint is also the standard connectivity check: it is cheap, read-only, and exercises authentication end to end.
Update the tenant
tenants:writeUpdates mutable tenant settings. Only name is mutable in v0.9; slug, reseller_id, and plan are not settable over the API.
New display name, 3–80 characters.
curl -X PATCH https://api.fibric.io/v1/tenant \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Acme Fulfillment, Inc."}'
Error cases:
| Status | Code | When |
|---|---|---|
400 | invalid_parameter | name fails validation, or the body carries an immutable field such as slug. |
403 | insufficient_scope | The calling key lacks tenants:write. |
Create a workspace
tenants:writeAdds a workspace partition. Workspaces are lightweight: they add a workspace_id dimension to objects and keys, not a second wall. Hard isolation, separate quotas, separate members, separate receipts, is a second tenant, not a workspace.
Slug-style name, unique within the tenant. Lowercase letters, digits, and hyphens; 3–40 characters.
curl -X POST https://api.fibric.io/v1/tenant/workspaces \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ws-create-eu-store" \
-d '{"name": "eu-store"}'
{
"id": "ws_9a44c2",
"object": "workspace",
"name": "eu-store",
"created_at": "2026-06-12T09:30:00Z"
}
Error cases:
| Status | Code | When |
|---|---|---|
400 | invalid_parameter | name is not a valid slug. |
409 | state_conflict | A workspace with this name already exists in the tenant. |
The member object
Members are the humans who sign in to the Fibric console: they approve plans, read receipts, and configure operators interactively. Members are distinct from API keys: a key authenticates a workload, a member authenticates a person, and both leave their identity in the audit trail (approver on receipts is a member email).
Unique identifier, prefixed mem_.
Always member.
The member's sign-in email, unique within the tenant.
viewer (read everything, act on nothing), approver (viewer plus approve, veto, undo), or owner (approver plus manage operators, connectors, guardrails, members, and keys).
invited until the member first signs in, then active. Removed members disappear from the list; their historical actions remain in receipts.
RFC 3339 timestamp of the invitation.
List members
tenants:readReturns the tenant's members, newest first, cursor-paginated with the standard limit and cursor parameters.
curl https://api.fibric.io/v1/tenant/members \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY"
{
"object": "list",
"data": [
{
"id": "mem_7f01d3",
"object": "member",
"email": "l.ops@example.com",
"role": "approver",
"status": "active",
"created_at": "2026-05-02T08:15:00Z"
}
],
"has_more": false,
"next_cursor": null
}
Invite a member
tenants:writeSends a console invitation. The member is invited until they first sign in.
The invitee's email address.
viewer, approver, or owner.
curl -X POST https://api.fibric.io/v1/tenant/members \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: invite-l.ops" \
-d '{"email": "l.ops@example.com", "role": "approver"}'
Error cases:
| Status | Code | When |
|---|---|---|
400 | invalid_parameter | email is not an email address, or role is not a known role. |
409 | state_conflict | A member with this email already exists in the tenant. |
Update a member
tenants:writeChanges a member's role. Demoting the tenant's only owner fails with 409 state_conflict: a tenant always retains at least one owner.
Remove a member
tenants:writeRemoves a member's console access immediately. Historical receipts naming the member as approver are unaffected; the audit trail does not rewrite. Removing the only owner fails with 409 state_conflict.
curl -X DELETE https://api.fibric.io/v1/tenant/members/mem_7f01d3 \
-H "Authorization: Bearer $FIBRIC_ADMIN_KEY"
Error cases for both endpoints:
| Status | Code | When |
|---|---|---|
404 | not_found | No member with this id exists in the tenant. |
409 | state_conflict | The change would leave the tenant with no owner. |