Baselyra Docs

Client libraries

Baselyra ships one official client, for JavaScript and TypeScript. Everything else is plain HTTP with JSON and three headers, which is why the Dart, PHP and Python pages here are complete hand-rolled clients rather than a promise of an SDK that does not exist.

What exists

LanguageStatus
JavaScript / TypeScriptOfficial@baselyra/client, zero dependencies. Browsers, Node 22, Deno, Bun, React Native.
Dart / FlutterA documented, complete plain-HTTP client to copy into your project
PHPA documented, complete plain-HTTP client
PythonA documented, complete plain-HTTP client
Anything elseThree headers and JSON. See below.

Which key goes where

KeyRoleWhere it may appear
anon keyanonAnywhere. A frontend bundle, a mobile binary, a public repository. It is meant to be public — row level security is what protects the data.
service keyservice_role, BYPASSRLSServer-side only. Never in a bundle, never in a NEXT_PUBLIC_* / VITE_* / EXPO_PUBLIC_* variable, never in a mobile app.

The HTTP contract

Three headers cover every language.

apikey: <anon key>                          # which Postgres role the request runs as
authorization: Bearer <user access token>   # who the user is; wins over apikey
content-type: application/json
You wantDo
Sign inPOST /auth/v1/token?grant_type=password with {email, password}
Renew a sessionPOST /auth/v1/token?grant_type=refresh_token with {refresh_token}
Read rowsGET /rest/v1/<table>?<filters>
Write rowsPOST / PATCH / DELETE /rest/v1/<table>
Call a functionPOST /rest/v1/rpc/<name> with the named arguments
Upload a filePOST /storage/v1/object/<bucket>/<key>
Watch changesWebSocket /realtime/v1?apikey=<token>

The error envelope

Every failure, from every prefix, has the same shape. Write one decoder and reuse it.

{"error":{"code":"unique_violation",
  "message":"duplicate key value violates unique constraint \"articles_slug_key\"",
  "details":{"detail":"Key (slug)=(hello) already exists.","hint":null,"sqlstate":"23505"}}}
FieldMeaning
codeA stable string — bad_request, unauthorized, unique_violation, statement_timeout. Branch on this, not on the message.
messageHuman-readable. Safe to show a developer; think before showing a user.
detailsnull, or an object. For a Postgres error it carries detail, hint and sqlstate.

Things every client should do

  • Store the rotated refresh token. Every refresh consumes its token and returns a new one. Replaying a spent token revokes the entire chain, and the user is signed out. This is the single most common bug in a hand-rolled client.
  • Refresh before the access token expires, not after a 401. An hour is the default lifetime, and a failure-driven refresh means every call site has to know how to replay itself.
  • Send a filter on every update and delete. The server refuses an unfiltered one, and that refusal is a feature — but a client that constructs the URL by hand should assert it too.
  • Read content-range for the total when you asked for Prefer: count=exact.
  • Percent-encode filter values. A literal + in a query string decodes to a space.

The JavaScript client

npm install @baselyra/client
import { createClient } from '@baselyra/client';

const bl = createClient('https://api.example.com', ANON_KEY);

const { data, error } = await bl.from('posts').select('id,title').eq('published', true);

Zero dependencies: fetch and WebSocket are the only platform features it uses, so the same build runs in browsers, Node 22, Deno, Bun and React Native with no polyfill and no bundler shim. The whole reference is on the JavaScript client page.

Framework guides

Anything else

Sign in, read, write, subscribe. That is the whole protocol.

# 1. sign in
curl -s -X POST "$URL/auth/v1/token?grant_type=password" \
  -H 'content-type: application/json' \
  -d '{"email":"ada@example.com","password":"…"}'

# 2. read as that user — RLS decides what comes back
curl -s "$URL/rest/v1/notes?select=id,title&order=created_at.desc" \
  -H "apikey: $ANON_KEY" -H "authorization: Bearer $ACCESS_TOKEN"

# 3. write
curl -s -X POST "$URL/rest/v1/notes" \
  -H "apikey: $ANON_KEY" -H "authorization: Bearer $ACCESS_TOKEN" \
  -H 'content-type: application/json' -H 'Prefer: return=representation' \
  -d '{"title":"From anywhere"}'

# 4. watch
websocat "wss://api.example.com/realtime/v1?apikey=$ACCESS_TOKEN"
{"type":"subscribe","channel":"public:notes"}

The full query language is on Filtering and paging, sessions on Auth, files on Storage and the socket protocol on Realtime.

Edit this page Report a problem

Esc
navigate open Esc close