You are reading v0, which is retired on 2026-06-30. It is kept online for existing integrations only. Read the v1 version.

Authentication

API keys for your own backend, OAuth for apps acting on a merchant's behalf, and the scope algebra both share.

Version v0 · updated 2026-02-01

On this page (3 sections)

There are exactly two ways to authenticate. Which one is correct is decided by a single question: does the credential belong to you, or to a merchant who has to consent to what you do with it?

API keyOAuth app
Use whenYou own the storeYou build for other merchants
Credential livesYour server, in a secret managerIssued per merchant, refreshable
ConsentImplicit (you are the owner)Explicit consent screen, revocable
ScopesChosen at key creationRequested ∩ allowed by registration
RotationManual, zero-downtime overlapRefresh token rotation on every use

API keys#

Send the key as a bearer token. Framique stores only a hash, so a lost key cannot be recovered — it is rotated. Rotation issues a second live key so you can deploy before revoking the first.

GET /api/public/v1/products?limit=25 HTTP/1.1
Host: framique.qubickle.com
Authorization: Bearer fq_live_9f2c…
Accept: application/json

OAuth 2.0 with PKCE#

Public clients (CLI tools, single-page apps) must use PKCE; there is no implicit flow and no client secret in a browser. Authorization codes are single-use and expire in 60 seconds, and a reused code revokes the whole grant family — a replayed code is treated as theft, not as a retry.

Exchange the code for tokens
curl -s -X POST "https://api.framique.com/api/public/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "'"$CODE"'",
    "client_id": "'"$CLIENT_ID"'",
    "code_verifier": "'"$VERIFIER"'",
    "redirect_uri": "https://app.example.com/callback"
  }'

Scopes#

Scopes are the same catalogue everywhere: the consent screen, the key editor and the gateway authorizer all read one table, so a scope cannot mean one thing on screen and another at the door. A `.write` scope implies `.read` of the same resource and nothing else.

GETproducts.read

/me

Identity of the calling credential

GETorders.read

/orders

List orders (cursor paginated)

GETorders.read

/orders/{id}

Fetch one order

POSTorders.write

/orders/{id}/notes

Append an order note

GETproducts.read

/products

List products (cursor paginated)

GETproducts.read

/products/{id}

Fetch one product

POSTproducts.write

/products

Create a draft product

GETcustomers.read

/customers

List customers (cursor paginated)

GETexports.read

/exports

List export jobs

POSTexports.write

/exports

Start an export job

GETexports.read

/exports/{id}

Export job detail + signed URL

GETwebhooks.read

/webhooks

List webhook endpoints

POSTwebhooks.write

/webhooks

Register a webhook endpoint

DELETEwebhooks.write

/webhooks/{id}

Delete a webhook endpoint

GETthemes.read

/themes

List installed themes

GETthemes.read

/themes/{id}

Fetch one installed theme

GETthemes.read

/themes/{id}/assets

List a theme's CSS, font and image assets

POSTthemes.write

/themes/{id}/activate

Activate a theme on the storefront

GETthemes.read

/marketplace/themes

List published marketplace themes