// workspace database

Workspace database

Every workspace can have a real managed Postgres behind it: your agent's durable memory, the table a pipeline writes into, the rows a dashboard view charts. Your agent reaches it through its own tools, and your backend reaches the same database over REST.

managed postgrespgvectorevery plan
01// what you get

What you get

A Postgres database scoped to the workspace, provisioned the first time something asks for it. There is no create step in your code: the first call provisions it if the organization has a plan, a credit package or a running trial.

On the no-card trial, the first use of the database starts the trial's 7-day clock if it is not running yet: any read, write or schema change from an agent, the API, a data job, an agent testing a dashboard query or the Database page in the superagnt app. Checking its status does not, and neither does opening a dashboard view.

Provisioning takes a moment, and the API tells you so in band rather than failing. While the database is coming up, every /v1/db/* route answers HTTP 202 with the current status and an instruction to retry.

202 while provisioningjson
{
  "success": true,
  "data": { "status": "provisioning" },
  "message": "Database is still provisioning. Retry shortly."
}

If the organization has none of those, the answer is HTTP 402 instead, naming the fix: choose a plan. Nothing is provisioned and nothing is charged.

02// serverless and dedicated

Two kinds of database

A serverless database is a Postgres database project of its own that sleeps when idle and wakes on the next call, reached only through our API. Every plan can have one. A dedicated database is a Postgres project of its own too. A workspace gets one or the other when its database is first created and keeps it. agnt_db_status reports which kind a workspace has in its backend field.

CapabilityServerlessDedicated
SQL, tables, rows, migrations and vector search (agnt_db_* tools and /v1/db routes)YesYes
File storage (/v1/db/storage/*)Not available on this databaseYes
Advisors (security and performance checks)Not available on this databaseYes
Migration historyKept in the database itself; agnt_db_list_migrations reads itKept in the project's migration history
Extensionspgvector, pgcrypto, pg_trgm and citext installed and callable unqualified; no othersThe project's own set
New tables locked with row-level securityNo; only our API connectsYes, automatically
Supabase auth helpers: auth.uid(), auth.role(), auth.jwt()No auth schema; keep user records in a table of your ownCallable in migrations (policies, column defaults, function bodies); nothing else in auth, auth.users included, and none of it outside migrations
Supabase platform schemas (storage, vault, cron, extensions and the rest)Not applicable: grants and extension changes are refused outrightOff limits: nothing can be moved into, granted across or changed in them. CREATE EXTENSION ... SCHEMA extensions still works
Plan limits on tables, rows and storageYes (below)No

On a serverless database, calls that are not available answer that they are not available on this database rather than failing silently, so an agent can tell a missing capability from a broken one.

03// from an agent

From an agent

Over MCP the database is the agnt_db_* family, served on the base connection with nothing to enable.

ToolWhat it does
agnt_db_statusIs the database provisioned and reachable (or paused), which kind it is, and its tables, rows and storage against the plan's limits.
agnt_db_list_tablesTables with their columns, types and RLS status.
agnt_db_list_extensionsInstalled Postgres extensions.
agnt_db_list_migrationsMigrations applied so far.
agnt_db_apply_migrationApply a named DDL migration.
agnt_db_execute_sqlRun SQL directly.
agnt_db_selectRead rows with filters and ordering.
agnt_db_insertInsert rows.
agnt_db_upsertInsert or update on conflict.
agnt_db_updateUpdate matching rows.
agnt_db_deleteDelete matching rows.
agnt_db_load_csvBulk-load a CSV already held in workspace files into a table.

deployed agents use their own path

A deployed agent does not call /v1/db/*. It reaches the same database through its runtime path, which is what keeps its table allowlist, its read-only setting and its audit attribution in force. Both surfaces run the same underlying implementation, so the contract is identical; only the policy layer differs.
04// from your backend

From your backend

/v1/db/* takes the same Authorization: Bearer <key> as the rest of the API and is scoped to that key's workspace.

RouteWhat it does
POST /v1/db/sqlRun SQL. Destructive statements need confirm; more than one statement needs allowMultiStatement; reads are capped at 1000 rows.
GET /v1/db/tablesList tables in the public schema.
GET /v1/db/tables/:nameColumns, types, nullability, defaults and indexes for one table.
POST /v1/db/tablesCreate a table from a column list.
PATCH /v1/db/tables/:nameAdd or drop columns. Dropping needs confirm.
DELETE /v1/db/tables/:nameDrop a table. Requires ?confirm=true.
GET /v1/db/rows/:tableRead rows with repeatable filter params, order, limit and offset.
POST /v1/db/rows/:tableInsert one row or a batch.
PATCH /v1/db/rows/:tableUpdate rows. Requires at least one filter.
DELETE /v1/db/rows/:tableDelete rows. Requires at least one filter.

Row reads take filter more than once, and the conditions are combined. Paging is limit and offset, not a cursor.

read rowsbash
curl "https://api.superagnt.com/v1/db/rows/leads?filter=status.eq.open&filter=score.gte.80&order=created_at.desc&limit=50&offset=0" \
  -H "Authorization: Bearer $AGNTDATA_API_KEY"
06// object storage

Object storage

A dedicated database carries buckets and objects under /v1/db/storage/*: list and create buckets, list objects by prefix with limit and offset, upload, download and delete. On a serverless database these routes answer HTTP 409: file storage isn't available on this database. Keep files in workspace files instead.

  1. 01

    Upload sends raw bytes

    POST /v1/db/storage/objects/:bucket?path=... takes the file as the raw request body, not a JSON field and not multipart. Set Content-Type to the file's own type; it is stored and replayed on download.

  2. 02

    Download streams the object itself

    GET /v1/db/storage/objects/:bucket/<path> returns the bytes with the object's own content type, not the usual JSON envelope. Do not try to parse it as JSON.

Everything else on the storage surface answers in the standard envelope.

07// limits

Limits on a serverless database

A serverless database is capped in tables, rows and storage, summed across every database the organization has. The no-card trial runs on Growth limits, and an organization on a managed plan or a credit package gets Scale limits on a serverless database.

PlanTablesRows, all tablesStorage
Starter1025,000250 MB
Growth50250,0001 GB
Scale2502,500,00010 GB
  1. 01

    Tables are checked up front

    A CREATE TABLE (or CREATE TABLE AS, SELECT INTO or a materialized view) that would pass the table cap is refused before it runs, with an upgrade offer. Partitions and materialized views count as tables. If the organization is over the cap, after a plan change for example, creating or altering anything is refused until tables are dropped or the plan goes up. Dropping a table still works.

  2. 02

    Rows and storage are measured, not metered

    Row counts and database size are measured as the database is used rather than on every insert, so a burst can pass a cap briefly. Storage is the database's size on disk, which includes a few megabytes of Postgres's own catalogs.

  3. 03

    A notice at 80%

    When any cap reaches 80%, agnt_db_status and the results of the other agnt_db_* tools carry a notice the agent can relay before anything is refused. The dashboard's Database page shows the same notice beside the usage meters.

  4. 04

    Storage never turns the database read-only

    Over the storage cap you get a notice, not a refusal. Some headroom is left past the cap; once it is used, a write that needs more space is refused with an offer for more storage, while reads and deletes keep working. Space freed by DELETE is reused after cleanup, and TRUNCATE or DROP TABLE frees it at once.

  5. 05

    Read-only for new data after 24 hours over

    A database that stays over its table or row cap for 24 hours stops taking new rows. Inserts, upserts and migrations are refused and raw SQL runs read-only, except SQL that only removes data: DELETE, TRUNCATE, and DROP of a table, view, materialized view, index or sequence still run (a request that mixes them with anything else runs read-only). Reads keep working, and so do row updates and deletes through agnt_db_update, agnt_db_delete and /v1/db/rows, so you can get back under on your own. A statement that only removes data but inserts rows on the way (through a trigger or a function) is rolled back. It lifts as soon as the database is back under the cap or the plan goes up.

  6. 06

    Synced vendor tables count too

    Tables a vendor sync keeps (named after the vendor, such as heyreach_conversations) count against these caps like any table you create. The Sync panel shows the tables and rows a sync would add before it is turned on, its event tables keep a rolling 90 days by default so they do not grow without bound, and the Database page breaks usage down by sync. Over the row cap a sync stops adding rows and keeps updating the ones it has.

when a trial or plan ends

When a trial ends without a plan, the database is kept, untouched, for 30 days, then deleted. When a paid plan lapses, the database is kept and everything pauses until a plan is active again. Either way, choosing a plan picks up exactly where it stopped.
  1. 01

    Paused, not deleted

    When the trial ends or a plan lapses, a serverless database is paused: nothing reaches it until a plan is active. Every call from an agent, the API or the dashboard answers with the offer to choose a plan (HTTP 402 with error.upgrade over REST, a requires_upgrade result over MCP), and the Database page says it is paused.

  2. 02

    Resumes within seconds of a plan

    Once a plan is active the database resumes on its own, usually within seconds. Until it has, calls answer HTTP 503 with a Retry-After header, and agnt_db_status reports it not ready with a hint to retry.

08// what it costs

What it costs

calls are free

The /v1/db/* routes deduct no data credits and write no usage rows. Query your own database as often as you like. What is priced is having a database at all.

Every plan includes the database. On the builder plans each workspace gets its own, so the plan's workspace count is the database count. On the managed plans the database count comes with the plan.

Managed planPriceDatabases
Solo$99/mo1
Team$199/mo3
Business$499/mo10
09// safety rails

Safety rails

The rails exist because the caller is often a language model, and the cost of a mistyped statement is your data.

  • Destructive SQL is refused unless the request says confirm. A DROP or a TRUNCATE has to be deliberate, not a side effect of a generated string.
  • More than one statement in a single POST /v1/db/sql needs allowMultiStatement, so a stray semicolon cannot smuggle a second command in.
  • Reads through POST /v1/db/sql are capped at 1000 rows, and the cap cannot be raised past that.
  • PATCH and DELETE on rows both require at least one filter. An update with no WHERE clause is not expressible on this surface.
  • DELETE on a table requires ?confirm=true on the URL.
  • On a serverless database, statements that change roles, grants or server settings, add extensions, or reach outside the database are refused, and every statement runs under a time limit.

agents should use the runtime surface

A workspace API key on /v1/db/* has the whole database. A deployed agent going through its runtime path is held to its own policy instead: only the tables on its allowlist, read-only when you set it that way, and every statement attributed to that agent in the audit trail. Give an agent the runtime surface and keep /v1/db/* for your own backend.

Dashboards over this data are on dashboards.