Skip to main content
The typed /api/* surface gives you opinionated, RPC-style access to the AI features. Underneath, all the state those endpoints manage lives in a single Postgres schema, ai, and PostgREST exposes that schema as a standard REST CRUD surface at /rest/v1/*. That means everything you can do with /api/agents, /api/sessions, /api/runs, /api/knowledge-bases, etc., you can also do directly against the underlying tables. SQL-style filters, joins, JSONB selectors, pagination via Content-Range, embeds: all the PostgREST machinery that powers public.* access works for ai.* too. This is the right tool when:
  • You need filters or joins the typed endpoint doesn’t expose (e.g., “all runs from the last 7 days where the agent’s system_prompt contains ‘refund’”).
  • You’re building a dashboard and want one query for usage analytics instead of N round-trips.
  • You’re bulk-tagging or migrating sources and don’t want to call PATCH /api/sources/{id} in a loop.
  • You want Realtime subscriptions on a state change the typed API doesn’t broadcast.
It’s not the right tool for state changes the platform’s own services manage (run lifecycle, indexing dispatch, workflow execution). Those endpoints aren’t just “a CRUD with extra steps”; they coordinate Celery tasks, RAG pipelines, and external LLM calls. Use the typed /api/* for state-changing operations on dynamic state, and PostgREST for reads and for writes on static, user-owned configuration.

How ai.* is exposed

PostgREST is configured to serve four schemas: public, storage, graphql_public, ai. The ai schema sits alongside your own public schema as a fully routed PostgREST surface. Every table follows the standard PostgREST URL pattern:
To target the ai schema instead of public, add the Accept-Profile (read) or Content-Profile (write) header:
Without Accept-Profile, PostgREST looks in the default public schema and 404s.

Tables in the ai schema

Every state-bearing entity in the AI surface has a corresponding table. The full list (35 tables): Schemas can grow; consult GET /rest/v1/ with Accept-Profile: ai for the live OpenAPI spec PostgREST emits.

RLS posture

Every ai.* table has Row Level Security enabled. The default policies are:
  • service_role: full access on every table (FOR ALL USING (true) WITH CHECK (true)). This is what the platform’s own backend uses.
  • authenticated (any signed-in GoTrue user): read access on every table. Write access on most user-configurable tables (agents, workflows, tools, knowledge_bases, sources, etc.). Per-user filtering on session-shaped tables (agent_sessions, agent_runs, orchestration_sessions, orchestration_runs) via auth.uid() = user_id.
  • anon: no access. Querying ai.* with the Anon (Publishable) Key returns empty result sets.
What this means in practice:
Multi-user projects: authenticated is project-wide, not per-user.The default policies grant authenticated blanket read access to every record in the project, including other users’ agents, workflows, and knowledge bases. Per-user scoping only applies to agent_sessions, agent_runs, orchestration_sessions, and orchestration_runs (where the user_id column lets auth.uid() filter).If your project has multiple end-users and you don’t want them seeing each other’s data, you must either (a) tighten the default policies, (b) gate ai.* reads behind your own backend with the Service Role key, or (c) only let end users hit /api/* (the typed surface enforces ownership where it matters).
See the RLS Model page for how auth.uid(), auth.jwt(), and the role mapping work, and the RLS Cookbook for concrete tightening patterns.

When to use PostgREST vs /api/*

Anything where the platform runs side-effects (Celery dispatch, LLM calls, file processing) belongs on the typed surface. Everything read-only or static-config belongs anywhere.

Next steps

ai-schema recipes

Four worked examples: hybrid search on chunks, usage analytics on runs, bulk source tagging, cross-KB joins.

RLS Model

How roles, JWT claims, and auth.uid() compose to gate ai.* and public.* access.

PostgREST Reference

Filter operators, embeds, headers, error responses.

Database Access

The three ways into your project’s Postgres — typed API, PostgREST, direct connection.