Bring your own database
Point an agent at a Postgres you already run, or at your own Supabase account. You write the GRANTs, so the ceiling on what an agent can do is a thing you can read before you run it, and revoke in one statement afterwards.
You create the role, you grant the access
Any reachable Postgres works: Supabase, RDS, a self-hosted instance. We provision nothing and hold no admin credential. You run a copy-paste preset against your own database, then paste the resulting DSN. Whatever the GRANTs allow is exactly what an agent can do, and nothing enforces a narrower rule on top.
| Preset | Role | What it grants |
|---|---|---|
read | agntdata_ro | SELECT on every table in public, now and in future. Analytics and read-only assistants. |
read_write | agntdata_rw | SELECT, INSERT, UPDATE, DELETE in public. No schema changes. |
full | agntdata_full | Adds CREATE, ALTER and DROP, via membership in the project's postgres role. |
custom | agntdata_custom | You pick the schemas, the tables and the operations. Nothing else is granted. |
The snippet names the Supabase SQL editor because that is the common case; the statements are plain Postgres and run anywhere.
-- 1) Replace <PASSWORD> with a strong password before running.
-- e.g. openssl rand -base64 24
-- 2) Paste this into your Supabase project's SQL editor and run it.
-- 3) Then copy the Transaction-pooler connection string from
-- Project Settings → Database, swap the username/password, and
-- paste the resulting DSN into agntdata's 'Self-provision' tab.
do $$
begin
if not exists (select 1 from pg_roles where rolname = 'agntdata_ro') then
execute format('create role %I login password %L', 'agntdata_ro', '<PASSWORD>');
else
execute format('alter role %I with login password %L', 'agntdata_ro', '<PASSWORD>');
end if;
end $$;
alter role "agntdata_ro" bypassrls;
grant usage on schema public to "agntdata_ro";
grant select on all tables in schema public to "agntdata_ro";
grant select on all sequences in schema public to "agntdata_ro";
alter default privileges in schema public grant select on tables to "agntdata_ro";
alter default privileges in schema public grant select on sequences to "agntdata_ro";
-- Bypass RLS so agent queries are not silently filtered. To enforce
-- RLS, change `bypassrls` above to `nobypassrls`.
-- Role created: agntdata_ro. Uninstall snippet is included in the dashboard.rls
bypassrls on, so policies written for browser sessions do not silently filter an agent's reads. Change it to nobypassrls in the snippet if you want RLS enforced against the role.- 01
Preview the SQL
The dashboard renders the exact statements for the preset you picked, with the password left as
<PASSWORD>for you to fill in. The Custom editor re-renders it as you change schemas, tables and operations, so you see the grants before you give them. - 02
Run it, then test the DSN
Run the snippet yourself, build the DSN for the new role, and use the dashboard's test action before saving. It opens a real connection so a bad DSN fails then and there, not on the first agent call.
- 03
Save
The DSN is encrypted at rest. From then on the connection answers on the REST routes below and on the
connection_postgres_*tools.
One statement per call
POST /v1/connections/postgres/query runs a single SQL statement. Multi-statement scripts have to come in as separate calls. Use $1, $2 placeholders and pass the values in params.
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sql | body | string | required | A single SQL statement. |
params | body | array | optional | Bind values, matched positionally to $1, $2, … |
row_cap | body | integer | optional | Maximum rows returned. Defaults to 1000, capped at 5000. |
statement_timeout_ms | body | integer | optional | Per-statement timeout. Defaults to 30000, capped at 60000, floor 1000. |
curl -s -X POST "https://api.superagnt.com/v1/connections/postgres/query" \
-H "Authorization: Bearer $AGNTDATA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sql": "select id, email from customers where created_at > $1 order by created_at desc",
"params": ["2026-01-01"],
"row_cap": 500
}'The result reports row_count and a truncated flag, so a caller can tell a short answer from a clipped one. Column types come back as raw Postgres OIDs in data_type_id.
Introspection
GET /v1/connections/postgres/schema returns the tables, columns, types and RLS status the role can see. Pass a comma-separated schemas query param to look beyond public. Prefer it over hand-rolled information_schema queries.
curl -s "https://api.superagnt.com/v1/connections/postgres/schema?schemas=public,billing" \
-H "Authorization: Bearer $AGNTDATA_API_KEY"Connecting an account grants access to nothing
Supabase projects are deny-by-default. Connecting the account lets you allowlist projects; it does not expose any of them. You add projects one at a time in the dashboard.
- A Management API call addressed at a project ref that is not on the allowlist returns a 403 naming the allowlist as the fix.
- The project list endpoint is filtered server-side, so an agent enumerating projects sees only the allowlisted ones. There is nothing to leak by asking.
Not through the Management API
hard-blocked
postgres role, which makes every per-table grant you set meaningless. It is not a data plane an agent gets.SQL goes through connection_supabase_query and connection_supabase_schema instead. Those connect over a scoped Postgres role provisioned per project from the per-table grants you pick in the dashboard, so a statement touching a table you did not grant fails at the database, not at a filter we wrote.
project_ref is optional on both tools. With one provisioned project it resolves on its own, and with several the error lists them, which is also how an agent discovers what it can reach.
Every query leaves a record
Each query and schema call writes an audit event carrying the actor, the surface it came from, the tool name and a truncated SQL preview. Bind values are deliberately not stored, because they routinely carry whatever the agent had in its prompt.
A usage row is written alongside it at zero cost. Your database is your database, so there is nothing to meter, but the call still shows up in usage so you can see the volume an agent is generating.
Two families, one per vendor
The database tools sit in their own families, vendor-db:postgres and vendor-db:supabase, separate from the HTTP connection:supabase family. They are gated on the connection existing, so a workspace never sees a database tool it has no database for, and picking one does not drag in the other.
| Tool | Does |
|---|---|
connection_postgres_query | One statement against the connected DSN. |
connection_postgres_schema | Introspect that database. |
connection_supabase_query | One statement against an allowlisted project, through its scoped role. |
connection_supabase_schema | Introspect that project. Only tables the role can reach are visible. |