The complete technical reference for connecting your apps to Fluxbase. Covers authentication, the SQL API, real-time WebSockets, file storage, team management, and row-level security.
Every Fluxbase integration requires three values, found in your Project Settings:
Bearer token from Settings → API Keys. Scoped per project.
Unique project identifier visible in the URL and Settings.
https://fluxbase.vercel.app — all REST endpoints live here.
wss://fluxbase-realtime.onrender.com — for real-time events.
FLUXBASE_API_KEY=flx_live_xxxxxxxxxxxxxxxxxxxx
FLUXBASE_PROJECT_ID=51c04beb753a42f3
NEXT_PUBLIC_WS_URL=wss://fluxbase-realtime.onrender.comAll REST API requests must include an Authorization header with a valid Bearer token. Requests missing this header return 401 Unauthorized.
Authorization: Bearer flx_live_xxxxxxxxxxxxxxxxxxxx
Content-Type: application/json| Scope | Access | Recommended For |
|---|---|---|
| read | SELECT only | Dashboards, public APIs |
| readwrite | SELECT, INSERT, UPDATE | Backend services |
| admin | Full DDL + DML access | Migration scripts, init scripts |
Execute any SQL statement against your project database via a single unified endpoint.
{
"projectId": "YOUR_PROJECT_ID",
"query": "SELECT * FROM users LIMIT 10;"
}{
"success": true,
"result": {
"rows": [
{ "id": 1, "name": "Alice", "email": "alice@example.com" }
],
"columns": ["id", "name", "email"],
"rowCount": 1,
"message": null
},
"executionInfo": {
"time": "11ms",
"rowCount": 1,
"operation": "SELECT"
}
}{
"success": false,
"error": {
"message": "relation "usrs" does not exist",
"code": "SQL_EXEC_ERROR",
"details": "ERROR: 42P01"
}
}success: false. Always check the success field — don't rely solely on HTTP status codes.| Field | Type | Required | Description |
|---|---|---|---|
| projectId | string | Yes | Your project's unique identifier. |
| query | string | Yes | The SQL statement to execute. Supports DDL and DML. |
| params | array | No | Optional parameterized values for $1, $2, … placeholders. |
No official SDK required — Fluxbase is a plain HTTP API. Here are copy-paste integration snippets for the most popular languages.
const BASE_URL = 'https://fluxbase.vercel.app';
const API_KEY = process.env.FLUXBASE_API_KEY;
const PROJECT = process.env.FLUXBASE_PROJECT_ID;
async function query(sql, params = []) {
const res = await fetch(`${BASE_URL}/api/execute-sql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
},
body: JSON.stringify({ projectId: PROJECT, query: sql, params }),
});
const json = await res.json();
if (!json.success) throw new Error(json.error?.message ?? 'Query failed');
return json.result.rows;
}
// Usage
const users = await query('SELECT id, name FROM users WHERE active = $1', [true]);
console.log(users);Fluxbase uses a persistent WebSocket connection to push live database events to connected clients. Subscribe once and receive row changes, schema updates, and custom broadcasts — with automatic reconnection.
Open one WebSocket and join a project room. All events are multiplexed over a single connection.
Get db_event messages for INSERT/UPDATE/DELETE and schema_update for DDL changes.
Built-in exponential backoff (1s → 2s → 4s → 15s max). Subscriptions restore automatically.
NEXT_PUBLIC_WS_URL=wss://fluxbase-realtime.onrender.comconst WS_URL = process.env.NEXT_PUBLIC_WS_URL ?? 'wss://fluxbase-realtime.onrender.com';
const PROJECT_ID = 'YOUR_PROJECT_ID';
let socket;
let reconnectDelay = 1000;
function connect() {
socket = new WebSocket(WS_URL);
socket.onopen = () => {
reconnectDelay = 1000; // reset on successful connection
socket.send(JSON.stringify({
type: 'subscribe',
roomId: `project_${PROJECT_ID}`,
}));
console.log('[WS] Connected and subscribed.');
};
socket.onmessage = ({ data }) => {
const msg = JSON.parse(data);
switch (msg.type) {
case 'subscribed':
console.log('[WS] Subscription confirmed.');
break;
case 'db_event': {
const { operation, table, record, old } = msg.payload ?? {};
if (operation === 'INSERT') console.log(`+ ${table}`, record);
if (operation === 'UPDATE') console.log(`~ ${table}`, { old, record });
if (operation === 'DELETE') console.log(`- ${table}`, record);
break;
}
default:
if (msg.payload?.event_type === 'schema_update') {
console.log('[WS] Schema changed — refresh your table list.');
}
}
};
socket.onclose = () => {
console.warn(`[WS] Disconnected. Reconnecting in ${reconnectDelay}ms...`);
setTimeout(connect, reconnectDelay);
reconnectDelay = Math.min(reconnectDelay * 2, 15000);
};
socket.onerror = (err) => console.error('[WS] Error:', err);
}
connect();| msg.type | payload details | When it fires |
|---|---|---|
| subscribed | — | Server confirmed room subscription. |
| db_event | operation: INSERT | A row was inserted via SQL or Table Editor. |
| db_event | operation: UPDATE | A row was modified. |
| db_event | operation: DELETE | A row was removed. |
| db_event | event_type: schema_update | DDL executed (CREATE / DROP / ALTER / RENAME / TRUNCATE). |
Secure AWS S3-backed file storage with logically isolated buckets, private-by-default access, and short-lived pre-signed URLs.
| Method | Endpoint | Action |
|---|---|---|
| GET | /api/storage/buckets?projectId=… | List all buckets + total size |
| POST | /api/storage/buckets | Create a bucket |
| PATCH | /api/storage/buckets | Rename a bucket |
| DELETE | /api/storage/buckets | Delete a bucket (must be empty) |
{
"projectId": "YOUR_PROJECT_ID",
"name": "profile-photos",
"isPublic": false
}
// Name rules: lowercase alphanumeric, hyphens, underscores, 1–63 chars| Method | Endpoint | Action |
|---|---|---|
| POST | /api/storage/upload | Upload file (multipart/form-data) |
| GET | /api/storage/files?bucketId=…&projectId=… | List files in a bucket |
| GET | /api/storage/url?s3Key=…&projectId=… | Get 15-min pre-signed download URL |
| DELETE | /api/storage/files | Delete a file (S3 + database) |
Send multipart/form-data — required fields: file, bucketId, projectId. bucketId accepts the bucket UUID or name.
curl -X POST "https://fluxbase.vercel.app/api/storage/upload" \
-H "Authorization: Bearer $FLUXBASE_API_KEY" \
-F "file=@avatar.jpg" \
-F "bucketId=profile-photos" \
-F "projectId=YOUR_PROJECT_ID"{
"success": true,
"file": {
"id": "uuid-here",
"name": "avatar.jpg",
"s3_key": "YOUR_PROJECT_ID/bucket-uuid/avatar.jpg",
"size": 204800,
}Manage project collaborators and send role-based invitations programmatically. All team endpoints require admin-level privileges.
{
"members": [
{ "userId": "usr_abc", "email": "alice@acme.com", "displayName": "Alice", "role": "admin", "joinedAt": "2026-01-10T09:00:00Z" }
],
"invites": [
{ "id": "inv_xyz", "email": "bob@acme.com", "role": "developer", "invitedAt": "2026-04-14T11:00:00Z" }
]
}{
"projectId": "YOUR_PROJECT_ID",
"email": "newmember@company.com",
"role": "developer"
}| Role | Permissions |
|---|---|
| admin | Full access — manage members, settings, billing, and data. |
| developer | Read/write data, manage schemas. Cannot manage billing or members. |
| viewer | Read-only access to data and the dashboard. |
{
"inviteId": "inv_xyz",
"status": "accepted"
}Webhooks are outbound HTTP POST requests sent from Fluxbase to your server when data events occur. Ideal for serverless functions (Vercel, AWS Lambda, Cloudflare Workers).
Register a Secret in your webhook config. Fluxbase signs every delivery with an X-Fluxbase-Signature HMAC-SHA256 header for you to verify.
{
"event_type": "row.inserted",
"project_id": "YOUR_PROJECT_ID",
"table_id": "orders",
"timestamp": "2026-04-14T12:00:00.000Z",
"data": {
"new": { "id": 123, "customer_id": 7, "amount": 59.99, "status": "pending" },
"old": null
}
}import crypto from 'crypto';
export async function POST(req) {
const rawBody = await req.text();
const sig = req.headers.get('x-fluxbase-signature') ?? '';
const secret = process.env.FLUXBASE_WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
if (sig !== `sha256=${expected}`) {
return new Response('Unauthorized', { status: 401 });
}
const event = JSON.parse(rawBody);
console.log('[Webhook]', event.event_type, event.data.new);
// Your business logic here...
return new Response('OK', { status: 200 });
}Fluxbase uses standard HTTP status codes alongside machine-readable error codes in the response body.
| HTTP Status | Error Code | Meaning & Fix |
|---|---|---|
| 401 | AUTH_REQUIRED | API key missing or malformed. Include Authorization: Bearer <key>. |
| 401 | TOKEN_EXPIRED | Session token has expired. Re-authenticate to get a new token. |
| 403 | SCOPE_MISMATCH | API key does not have access to this project or resource. |
| 403 | PROJECT_SUSPENDED | Project is suspended due to plan limits or billing. Upgrade your plan. |
| 403 | INSUFFICIENT_PERMISSIONS | Only admins can perform this action (e.g., inviting members). |
| 404 | PROJECT_NOT_FOUND | No project found for the given projectId. Check your ID. |
| 404 | USER_NOT_FOUND | Invitee email does not match any registered Fluxbase account. |
| 429 | RATE_LIMIT | 50 requests per 10 seconds exceeded. Implement exponential backoff. |
| 500 | INTERNAL_ERROR | Unexpected server error. These are logged and auto-reported. |
| 503 | DATABASE_CONNECTION_ERROR | Transient database connectivity issue. Retry after a few seconds. |
| 200 | SQL_EXEC_ERROR | SQL syntax or logic error. Check the error.details field for the Postgres error. |
Your logged-in user ID is injected via SET LOCAL fluxbase.auth_uid before each query.
PostgreSQL runs your USING expression (e.g. user_id = auth.uid()) before returning any row.
Rows that fail the policy are silently excluded — no errors, just scoped results.
Navigate to Database → Row Level Security in your project sidebar. All tables are listed.
Choose a table, select command scope (ALL / SELECT / INSERT / UPDATE / DELETE), then write your USING expression.
Toggle the switch. Fluxbase immediately runs ALTER TABLE … ENABLE ROW LEVEL SECURITY and CREATE POLICY.
Run SELECT * FROM your_table — you'll only see rows that pass the policy for the authenticated user.
Classic pattern for posts, orders, and profiles.
user_id = auth.uid()All members of an organization share visibility. Set auth.uid() to the org ID at the API level.
org_id = auth.uid()Create two policies on the same table with different command scopes.
trueauthor_id = auth.uid()Useful for internal audit tables that no API caller should read.
false| Problem | Cause | Fix |
|---|---|---|
| Query returns 0 rows | Policy never matches | Temporarily set USING to true to confirm RLS is the cause. |
| Policy toggle fails | Column in expression missing | Ensure user_id (or the referenced column) exists in the table. |
| User can't see own rows | Type mismatch (INT vs TEXT) | Cast explicitly: user_id::text = auth.uid() |
| Admin locked out | FORCE ROW LEVEL SECURITY active | Run ALTER TABLE … NO FORCE ROW LEVEL SECURITY in the SQL Editor. |
Our team is available for architecture reviews and custom integration support.