Skip to main content

The two keys

Every project gets exactly two API keys when it is created.
KeyPrefixWhere to useDefault write access
Publishable keypk_live_...Frontend, browser, mobile appRead-only — writes blocked unless RLS is enabled
Secret keysk_live_...Server-side only (Node.js, serverless functions, etc.)Full read and write access
Both keys are found in Settings in your project dashboard.

How to pass the key

Include the key in the x-api-key request header on every API call:
x-api-key: pk_live_...
No other authentication format is accepted for project-level authorization. The header name is lowercase and hyphenated exactly as shown.

Using the publishable key

Use pk_live for all read operations from client-side code. It is safe to bundle in browser JavaScript, React Native apps, or any publicly visible context.
// Safe — pk_live is read-only by default
const response = await fetch('https://api.ub.bitbros.in/api/data/products', {
  headers: {
    'x-api-key': 'pk_live_...'
  }
});

const { data } = await response.json();
By default, pk_live is blocked from all write operations (POST, PUT, PATCH, DELETE). Attempting a write with only pk_live returns:
{ "success": false, "message": "Write blocked for publishable key" }

Enabling writes with pk_live

You can allow authenticated frontend users to write their own data by enabling Row-Level Security (RLS) on a collection. When RLS is on, pk_live writes are accepted — but only when the request also includes a valid user JWT in the Authorization header, and only for documents the user owns.
// pk_live write with RLS enabled — user must be logged in
const response = await fetch('https://api.ub.bitbros.in/api/data/posts', {
  method: 'POST',
  headers: {
    'x-api-key': 'pk_live_...',
    'Authorization': `Bearer ${userToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ title: 'My post', content: '...' })
});
See Row-Level Security for the full setup and behavior details.

Using the secret key

Use sk_live for all server-side operations: seeding data, admin scripts, serverless API routes, and any write that happens outside a user’s own browser session.
// Server-side only — never expose sk_live in client code
const response = await fetch('https://api.ub.bitbros.in/api/data/products', {
  method: 'POST',
  headers: {
    'x-api-key': 'sk_live_...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Widget', price: 9.99 })
});
sk_live bypasses RLS entirely and always has full read and write access on all collections (except /api/data/users*, which is always blocked — use /api/userAuth/* instead).
Never include your sk_live key in frontend code, client-side JavaScript bundles, mobile apps, or any public repository. Treat it like a database password. If it is exposed, rotate it immediately from your project settings.

Environment variable pattern

Store your keys in environment variables and never commit them to source control:
# .env (add to .gitignore)
VITE_URBACKEND_KEY=pk_live_xxxxxx   # safe to expose to the browser via VITE_
URBACKEND_SECRET=sk_live_yyyyyy      # server-side only, never prefix with VITE_
// In your frontend code
const apiKey = import.meta.env.VITE_URBACKEND_KEY; // pk_live

// In your server/API route
const secretKey = process.env.URBACKEND_SECRET; // sk_live

Key behavior summary

ScenarioKeyTokenResult
Read any collectionpk_liveNot requiredAllowed
Write, RLS disabledpk_liveAny403 blocked
Write, RLS enabled, no tokenpk_liveMissing401 unauthorized
Write, RLS enabled, correct ownerpk_liveMatching userIdAllowed
Write, RLS enabled, wrong ownerpk_liveDifferent userId403 owner mismatch
Any writesk_liveNot requiredAllowed
Access /api/data/users*AnyAny403 blocked — use /api/userAuth/*
A good rule of thumb: use pk_live for everything your users’ browsers do, and sk_live for everything your server does.