Authentication
How to get an API key, how to send it, and what its scopes decide.
Getting a key
API keys are created per organization, not per user — a key outlives whoever created it, so removing someone from your team does not revoke the integration they set up.
Create one in Fabric under Organization → API keys. Choose the scopes it needs; you cannot widen them later, so a key that outgrows its scopes is replaced rather than edited.
A key is shown once, when it is created. It is stored hashed, so it cannot be recovered — only replaced. Keep it somewhere your team can find it and your repository cannot.
Your first call
GET /v1/me needs no scope beyond a valid key and answers with the organization the key belongs
to. It is the fastest way to prove a key works before you write anything real against it.
curl https://fabric.inc/api/v1/me \
-H "Authorization: Bearer fab_sk_..."{
"apiKeyId": "key_...",
"organization": { "id": "org_...", "name": "Acme", "slug": "acme" },
"role": "member",
"scopes": ["catalog:read", "catalog:write"],
"brands": [
{ "id": "brd_...", "name": "Acme Outdoor", "isDefault": true, "mainDomain": "acme.com" }
]
}A 200 there means the key, the header and the base URL are all right. From that point every
failure is about the specific request rather than your setup.
It also answers the question every other endpoint asks first: brands is where a brandId
comes from. A key carrying no scopes gets its own identity but an empty brands list — it can
tell you what it is, not what the organization owns.
Reading your own scopes back is what makes a later
insufficient_scope self-diagnosable rather than a guess.
Sending it
Either header works. Use whichever your HTTP client makes easy:
curl https://fabric.inc/api/v1/me \
-H "Authorization: Bearer fab_sk_..."curl https://fabric.inc/api/v1/me \
-H "X-Api-Key: fab_sk_..."If both are present, the bearer token wins.
Scopes
A key carries scopes, and every endpoint requires one. A call without it returns
insufficient_scope, naming what was missing.
| Scope | Grants |
|---|---|
catalog:read | Read products, values, attributes, categories, views and lists |
catalog:write | Create and change them, including archiving and deleting |
enrichment:write | Start enrichment runs, spend credits, write guidelines, review values |
publishing:read | Read destination connections, mappings and their history, publishing runs; preview a mapping and download an export |
publishing:write | Create connections and mappings, start and approve publishing runs |
org:read | Read the organization, its brands, its members and its API keys |
org:write | Change organization settings, manage keys and webhook endpoints |
There is no hierarchy. catalog:write does not confer catalog:read — a grant should be
readable off the key rather than derived, so an audit answers "what can this key do" by looking.
The creation screen pairs the two by default, which is where the convenience belongs.
Anything unrecognised on a key is ignored rather than honoured, so a hand-written scope grants nothing.
Roles
Scope is necessary, never sufficient. The key also carries its organization role, enforced exactly as it is for a person:
| Role | Can | Cannot |
|---|---|---|
member | Read everything in the organization, create connections and mappings, run a dry run, download a file export | Approve a publish to a feed or storefront; activate a mapping version; set a global config default |
owner | Everything | — |
A key holding publishing:write on a member role still cannot approve a publish. Both checks must
pass, and they fail with different codes. A missing scope is always
insufficient_scope. A role is
forbidden, except on the publishing operations — approving a publish,
activating a mapping version — which check the role inside the operation and answer
refused.
An owner key can approve its own publish
A single call with approve: true both approves and publishes to a live storefront. That is the
intended contract — an owner-scoped key is your organization's consent — but it means such a
key is a production-write credential. Prefer the narrowest scopes and a member role for
anything that only needs to read or prepare.
Organization boundary
Everything a key can reach belongs to its organization. There is no cross-organization access and
no way to widen a key's reach; a second organization needs a second key. A resource outside it
answers not_found rather than forbidden, so an id you do not own is
never confirmed.
Rotation and revocation
Revoke a key from the same screen and it stops working immediately — revocation is instant, not a cache expiry. Runs and mapping versions the key created keep resolving afterwards: the audit trail records which key acted, and revoking one does not erase what it did.
Rotate by creating the replacement first, moving your integration over, then revoking the old one. There is no overlap limit.