REST and GraphQL
Read and write tables over HTTP.
Every table in the database's exposed schemas (public unless you add more) gets REST endpoints at:
https://api.clouzark.com/rest/<database ref>Find the URL and keys with clouzark db keys.
Use supabase-js
Each database also speaks PostgREST's API, so supabase-js (or the smaller @supabase/postgrest-js) works against it. Use the project URL from clouzark db keys as the Supabase URL:
import { createClient } from '@supabase/supabase-js';
const db = createClient('https://api.clouzark.com/projects/<database ref>', process.env.NEXT_PUBLIC_CLOUZARK_ANON_KEY!);
const { data, error } = await db
.from('posts')
.select('id, title, author:authors(name), comments(body)')
.eq('published', true)
.gt('views', 100)
.order('created_at', { ascending: false })
.range(0, 19);
await db.from('posts').insert({ title: 'Hello' }).select().single();
await db.from('posts').upsert({ id: 1, title: 'Updated' });
await db.from('posts').update({ published: true }).eq('id', 1);
await db.from('posts').delete().eq('id', 1);
const { data: total } = await db.rpc('add', { a: 2, b: 3 });Supported: every filter (eq, neq, gt, gte, lt, lte, like, ilike, match, in, is, contains, containedBy, overlaps, textSearch, or, not, filter), JSON paths (meta->>country), casts, embedding over foreign keys (nested, aliased, !inner, with their own filters, order, and limit), count (exact, planned, estimated), single() and maybeSingle(), insert, upsert, update, delete with select(), and rpc() for functions (get: true for read-only ones). Errors use PostgREST's codes, such as PGRST116 and 23505.
Only the database part of supabase-js (from(), rpc(), schema()) works against Clouzark. For sign-in, files, and realtime use Auth, Storage, and Realtime. To send a signed-in user's token, pass it in global.headers.Authorization. Many-to-many embedding through a join table and spread embeds (...) aren't supported.
The endpoints below (/rest/<ref>) keep working as they are.
Authentication
Send one of:
apikey: <anon key>— browsers and mobile apps. Row-level security applies.apikey: <service key>— server-side only. Bypasses row-level security.Authorization: Bearer <user token>— acts as a signed-in user from Auth.
Endpoints
| Request | Returns |
|---|---|
GET /rest/<ref> | { tables } |
GET /rest/<ref>/<table>?page=1 | { columns, rows, total, pageSize }, 50 rows per page |
GET /rest/<ref>/<table>/<id> | { row } |
POST /rest/<ref>/<table> with a JSON row | { row } (201) |
PATCH /rest/<ref>/<table>/<id> with the changed columns | { row } |
DELETE /rest/<ref>/<table>/<id> | 204 |
Errors come back as { "error": "..." }.
const base = 'https://api.clouzark.com/rest/my-app-db';
const headers = { apikey: process.env.NEXT_PUBLIC_CLOUZARK_ANON_KEY!, 'Content-Type': 'application/json' };
const { rows } = await fetch(`${base}/orders?page=1`, { headers }).then((r) => r.json());
const { row } = await fetch(`${base}/orders`, {
method: 'POST',
headers,
body: JSON.stringify({ total_cents: 4200 }),
}).then((r) => r.json());Schemas
By default the APIs serve the public schema. To serve others, check them under Settings → Exposed schemas; the list also shows which tables in each schema have row-level security off, because the anon key can read and write every row in those once the schema is exposed.
Pick the schema per request, as with PostgREST: Accept-Profile on GET, Content-Profile on POST, PATCH, and DELETE. Without the header, the first exposed schema is used. A schema that isn't exposed returns 406.
await fetch(`${base}/jobs`, { headers: { ...headers, 'Accept-Profile': 'career' } });
await fetch(`${base}/jobs`, {
method: 'POST',
headers: { ...headers, 'Content-Profile': 'career' },
body: JSON.stringify({ title: 'Engineer' }),
});Row-level security
With the anon key or a user token, Postgres row-level security decides what each request can see and change. Enable it on every table your app exposes, and write policies with auth.uid(), which returns the signed-in user's id (or null):
alter table orders enable row level security;
create policy "read own orders" on orders
for select using (user_id = auth.uid());
create policy "create own orders" on orders
for insert with check (user_id = auth.uid());GraphQL
The same data is available over GraphQL, with the same keys and policies:
POST https://api.clouzark.com/graphql/<database ref>
{ "query": "...", "variables": { } }GraphQL covers every exposed schema. Tables outside public are prefixed with their schema, so career.jobs is queried as career_jobs.