Fabric documentation

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:

Authorization
curl https://fabric.inc/api/v1/me \
  -H "Authorization: Bearer fab_sk_..."
X-Api-Key
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.

ScopeGrants
catalog:readRead products, values, attributes, categories, views and lists
catalog:writeCreate and change them, including archiving and deleting
enrichment:writeStart enrichment runs, spend credits, write guidelines, review values
publishing:readRead destination connections, mappings and their history, publishing runs; preview a mapping and download an export
publishing:writeCreate connections and mappings, start and approve publishing runs
org:readRead the organization, its brands, its members and its API keys
org:writeChange 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:

RoleCanCannot
memberRead everything in the organization, create connections and mappings, run a dry run, download a file exportApprove a publish to a feed or storefront; activate a mapping version; set a global config default
ownerEverything—

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.