Authentication
How to authenticate calls to the Brainerce API — pick the right mode for your use case.
Brainerce supports five authentication modes. Pick exactly one per request:
1. Admin API key — server-to-server
Use for backend integrations (ERPs, custom tooling, server-rendered storefronts that need write access).
Authorization: Bearer brainerce_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or, equivalently:
X-API-Key: brainerce_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- Both headers are accepted.
X-API-Keyis checked first, thenAuthorization: Bearer; either must carry a value starting withbrainerce_. PreferAuthorization: Bearer— it is what the SDK sends and what the rest of these docs assume. Do not send both. - Issue keys from Settings → Authentication → API Keys in the dashboard. Plain-text key is shown once — store it in your secret manager.
- Keys are scoped (e.g.
products:read,orders:write). Wildcard*scope is no longer mintable — list exactly the scopes your integration needs. Note that scope matching supports{resource}:*(e.g.products:*) but not*:read— a key holding*:readmatches nothing and every call fails withINSUFFICIENT_SCOPE. - Keys never expire unless you set
expiresAt. Rotate via Settings → API Keys → Rotate (zero-downtime). - All
/api/v1/*endpoints require this mode.
Never put an admin key in client JavaScript. CORS will not save you — admin keys are blast-radius credentials and a leaked key = full store access.
2. Sales channel — vibe-coded storefronts
Use for storefronts built by AI agents or custom Next.js/React apps deployed to a specific domain.
GET /api/vc/vc_xxxxxxxxxxxxxxxxxxxxxx/products
Origin: https://your-storefront.com- The sales channel ID (
vc_…) is path-based, not a header.salesChannelIdis the canonical name for it;connectionIdis a deprecated alias that still appears as the literal route parameter in generated reference pages — the value is the samevc_*string either way. - Live mode requires an
Originheader, and its host must match the channel's registereddomain(host equality or a subdomain). A LIVE request with noOriginis rejected, so server-side rendering against a LIVEvc_*channel does not work — see Rules. - Test mode accepts any origin only while the channel has no
domainset; once a domain is configured it is matched exactly as in live mode. Test mode is not read-only — it is the same API surface as live, against the same store data, governed by the same per-channel scopes. - Scopes are per-channel (
storefrontReadEnabled,cartEnabled,customerAuthEnabled,ordersWriteEnabled, …).
3. Storefront public — public catalog reads
Use for embedded widgets, marketing pages, and discovery flows that only need to read products/categories/store info.
GET /api/stores/store_xxxxxxxxxxxxxxxxxxxxx/products- No credential. Read-only. Public catalog data only.
- Origin must be present (browser-context only — server-side scripts should use mode 1 or 2).
4. Customer JWT — on behalf of a logged-in shopper
Layered on top of mode 2 or 3 for customer-scoped operations (cart, order history, account).
Authorization: Bearer eyJhbGciOi... # customer JWT (NOT a Clerk JWT)- Obtained via
POST /api/vc/{salesChannelId}/customers/loginor OAuth. - 7-day expiry by default.
- Use alongside the sales-channel path; the JWT carries
customerId.
5. App Installation Tokens
Use for marketplace apps — server-side integrations that a merchant has installed onto their store via the dashboard. The token is bound to one AppInstallation row and carries only the scopes declared by the app's manifest.
Authorization: Bearer app_inst_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or
X-API-Key: app_inst_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-
Format:
app_inst_+ 32+ random characters. Issued automatically when a merchant installs an app from the marketplace; the plain-text token is delivered to the app's setup URL once and stored encrypted at rest. -
Scopes are app-declared (e.g.
mappings:read,mappings:write,config:write) and cannot be escalated by the app at runtime. -
Routes accepting this mode all live under
/api/v1/installations/{installationId}/*. Today that's:Method Path Scope PUT/v1/installations/{installationId}/secretsconfig:writePOST/v1/installations/{installationId}/mappingsmappings:writeGET/v1/installations/{installationId}/mappingsmappings:readGET/v1/installations/{installationId}/mappings/{mappingId}mappings:readPATCH/v1/installations/{installationId}/mappings/{mappingId}mappings:writeDELETE/v1/installations/{installationId}/mappings/{mappingId}mappings:writePUT/v1/installations/{installationId}/mappings/upsertmappings:write -
The
installationIdin the URL must match theinstallationIdcarried by the token — a 403 is returned otherwise. One app cannot read or write another app's installation data. -
Rate limit: per-installation tier (
BRAINERCE1000/min,ECOMMERCE_PLATFORM500/min, third-party 100/min). Responses includeX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset, andRetry-Afteron 429. -
For the SDK surface see the SDK reference.
What you cannot do
- Mix two credentials in one request. Sending both
Authorization: Bearer brainerce_*andX-API-Key: app_inst_*is rejected. - Use a Clerk dashboard JWT against
/api/v1/*. Clerk JWTs are dashboard-only; integrators get API keys. - Reuse a leaked key with the same prefix. The
keyPrefixshown in the dashboard is only the first 12 characters — the rest is unrecoverable. Rotate immediately if leaked.
Rate limits per mode
See Rate Limits for the full table. Quick summary:
| Mode | Limit enforced today |
|---|---|
| Admin API key | 60/min + 1000/hour per IP, plus a per-key quota by tier: FREE 60, PRO 500, GROWTH 2000, ENTERPRISE 10000 req/min |
| App installation | 60/min + 1000/hour per IP, plus 100–1000/min per installation by app tier |
| Sales channel | 60/min + 1000/hour per IP. Individual routes (login, register, forgot-password, review submit, …) set their own tighter caps, down to 3/min |
| Storefront | 60/min + 1000/hour per IP, same per-route overrides |
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds remaining, not a Unix timestamp), plus Retry-After on a 429.
Per-key quotas are live, not planned. Per-channel quotas are the ones that do not exist — a sales channel has no rate-limit override of its own, so a busy storefront is bounded by the per-IP tiers and the per-route caps.