Data API

The schema model for app-private dynamic tables, and the HTTP data API for reading and writing rows from outside the app

AxHub apps store data in app-private dynamic tables — no separate database to wire up. Each app gets an isolated PostgreSQL schema where you define tables and columns and CRUD rows. This page covers the schema model and the HTTP data API you call from outside the app. Inside the app the SDK is simpler (see Call the backend with the SDK); for a step-by-step walkthrough see the Dynamic tables guide.

Access model

The data surface splits into two sides with different authentication.

OperationAuth
DDL — create/alter tables, columns, grantsLogin (OAuth) only
Data — read/write rowsLogin (OAuth) or PAT (X-Api-Key)
  • In-app code → SDK (acts as the signed-in user, simplest)
  • Outside the app (agents, CI, server-to-server) → HTTP data API + PAT

Creating and managing tables (DDL) can't be done with a PAT — it needs a login. PATs are for reading and writing data only.

Schema model

A table is defined by its columns. The column format is name:type[:nullable][:default].

axhub tables create orders --app demo \
  --column 'title:text' \
  --column 'qty:int' \
  --column 'done:bool:true:false' \
  --execute

There are 8 column types.

TypeDescription
textString
int · bigintInteger
floatFloat
boolBoolean
timestamptzTimestamp with time zone
uuidUUID
jsonbJSON
  • owner-column--owner-column <column> marks the column that identifies a row's owner.
  • description — a table description is capped at 1000 bytes (~1000 ASCII chars).
  • For many columns, pass a schema file with --schema table.yaml.

Data API endpoints

To work with rows from outside, call HTTP directly. The path is /data/{tenant}/{app}/{table} and the base is https://api.axhub.ai.

Method · PathDoes
GET /data/{tenant}/{app}/{table}List rows
GET …/{table}/_countCount rows
GET …/{table}/{id}Get one row
POST …/{table}Insert a row
PATCH …/{table}/{id}Update a row
DELETE …/{table}/{id}Delete a row
const base = `https://api.axhub.ai/data/${tenant}/${app}/orders`;
const headers = { 'X-Api-Key': process.env.AXHUB_API_KEY, 'Content-Type': 'application/json' };

const rows = await fetch(base, { headers }).then((r) => r.json());        // list
await fetch(base, {                                                        // insert
  method: 'POST', headers, body: JSON.stringify({ title: 'First order', qty: 2 }),
});

Query parameters

List (GET) and count (_count) accept these query parameters to filter and sort.

ParameterDescription
filterBackend DSL: col=value or col=op.value (e.g. qty=gt.10)
selectColumns to return, comma-separated
sortSort columns, comma-separated; prefix with - for DESC (e.g. -created_at)
page · per_pagePagination (per_page max 200)

To insert many rows at once, send JSONL (one JSON object per line). Batch insert requests are throttled to 200/min.

Table grants

By default a table is reachable only by the app that created it. To open read/write access to another app or principal, issue a table grant.

axhub tables grants issue --app demo --table orders \
  --principal-type <principal kind> --principal-id <principal id> \
  --actions read,write --execute

axhub tables grants list   --app demo --table orders
axhub tables grants revoke --app demo --table orders --grant-id <grant id>

A grant is a principal plus actions — who (principal-type·principal-id) can do what (read/write, etc.).

Security & errors

  • A PAT (X-Api-Key) is a secret. Don't hard-code it — store it as a runtime secret in environment variables and read it on the server.
  • DDL is not allowed with a PAT — table, column, and grant changes require a login (OAuth).
  • Responses are JSON; failures are traceable via X-Request-Id. Automation should prefer HTTP status + request id over localized messages.