Appbricx
Docs
FeaturesPricingStart free

Get started

OverviewWhat Appbricx isQuickstart with a coding agentQuickstart with the builderCore concepts

Guides

Data and tablesAccess and rolesBusiness rulesSign-inCustom screensRealtime and topicsWorkflows, schedules and webhooksServer functionsAI in your appPaymentsFilesMessagesIntegrationsVerifyPublishing, domains and rollbackOperating your appExport and self-hostSelf-host install

Tutorials

Build a booking app with Claude CodeMulti-user todo listClient portalSlack on new sign-upTemplates

Reference

Reference homeFrontend SDKHTTP APIMCP toolsCLIIntegrations catalogContract formatAI key resolutionRun Appbricx locally

Data API

List, read, create, update and delete rows of the app's tables, plus aggregates, full-text search, lifecycle transitions, external tables, named queries and raw SQL for trusted backends.

21 endpointsHTTP API referenceGuide: REST API for your data

On this page
  1. Authentication
  2. Endpoints
  3. GET /queries
  4. POST /queries/*
  5. GET /api/v1/search
  6. GET /api/v1/openapi.json
  7. GET /api/v1/:table
  8. GET /api/v1/:table/aggregate
  9. GET /api/v1/:table/:id
  10. POST /api/v1/:table
  11. PATCH /api/v1/:table/:id
  12. DELETE /api/v1/:table/:id
  13. GET /api/v1/ext/:entity
  14. GET /api/v1/ext/:entity/aggregate
  15. GET /api/v1/ext/:entity/:id
  16. POST /api/v1/ext/:entity
  17. PATCH /api/v1/ext/:entity/:id
  18. DELETE /api/v1/ext/:entity/:id
  19. PATCH /api/v1/:entity/:id/transition
  20. POST /data/query
  21. POST /data/exec
  22. POST /data/schema
  23. POST /data/migrate

Base URL: your app's origin ($APP_ORIGIN): the published host, a custom domain, or the platform origin for the builder preview. Errors answer { ok: false, error: { code, message } } unless noted. Add x-appbricx-env: dev or prod to pick the database explicitly; otherwise the host decides (preview means dev, a published host means prod).

Authentication

App key + data marker
A project API key (dpk_c_… in browsers, bound to the app's origins; dpk_s_… on servers) or the builder preview token, plus the data-API marker header. With an app session (the header, or the appbricx_app_session cookie) the call acts as that user under row-level security; without one it acts as a guest. A server key may assert x-appbricx-app-user, x-appbricx-app-role and x-appbricx-app-org. Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)
App key + signed-in user
A project key or preview token and a signed-in app session (header or cookie). Signed-out callers get 401. Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION
Server key
A server-tier project API key (dpk_s_…, created in the editor under Backend, API). Browser keys and end-user sessions are refused. Authorization: Bearer $SERVER_KEYx-appbricx-data-api: 1

Endpoints

List named queries

GET/__appbricx/queries

The app's named queries with their descriptions and declared parameters.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Response

Response
{
  "ok": true,
  "queries": [
    {
      "name": "reports/monthly",
      "description": "Revenue per day",
      "params": {
        "month": {
          "type": "string",
          "required": true
        }
      },
      "allow": [
        "end_user",
        "workflow"
      ]
    }
  ]
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
curl
curl "$APP_ORIGIN/__appbricx/queries" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/queries`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

RelatedGuides data

Source: services/api/src/app-runtime/http/queries-routes.ts:51

Run a named query

POST/__appbricx/queries/*

Run a named query (a .sql file kept on the server) with parameters. The path after /queries/ is the query name; folders are allowed (reports/monthly, or URL-encoded).

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
*requiredstringThe query name.

Body

NameTypeDescription
paramsoptionalobjectDeclared parameters. A flat body is read as the parameter map too.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "day": "2026-10-01",
      "revenue": 812
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "day",
      "type": "1082"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
400PARAMS_INVALIDInvalid query name, or a missing / mistyped parameter.
404(query error)"Unknown query".

An admin app session plus x-appbricx-admin: 1 elevates SELECT queries so dashboards can read across users. Mutations stay row-scoped.

curl
curl -X POST "$APP_ORIGIN/__appbricx/queries/reports/monthly" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION" \
  -H "content-type: application/json" \
  -d '{"params":{"month":"2026-10"}}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/queries/reports/monthly`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "params": {
      "month": "2026-10"
    }
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedctx.queries.run

Source: services/api/src/app-runtime/http/queries-routes.ts:64

Full-text search

GET/__appbricx/api/v1/search

Ranked full-text search over the generated search vectors of the tables you name, under the caller's row-level security.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Query parameters

NameTypeDescription
qrequiredstringSearch text (web-search syntax: quotes, OR, -word).
tablesrequiredstringComma-separated table names (up to 20). Tables the role may not read are skipped.
limitoptionalnumberRows per table (default 5, max 25).

Response

Response
{
  "ok": true,
  "results": [
    {
      "table": "tickets",
      "rows": [
        {
          "id": "8c1d…",
          "title": "Printer jam"
        }
      ]
    },
    {
      "table": "assets",
      "rows": []
    }
  ]
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
400MISSING_QUERYq is empty.
400MISSING_TABLEStables is empty.
curl
curl "$APP_ORIGIN/__appbricx/api/v1/search?q=printer&tables=tickets%2Cassets&limit=5" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/search?q=printer&tables=tickets%2Cassets&limit=5`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/queries-routes.ts:142

OpenAPI document

GET/__appbricx/api/v1/openapi.json

The app's OpenAPI 3.1 document: every table, its schema and the role matrix. No data. Import it into Postman or a client generator.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Response

Response
{
  "openapi": "3.1.0",
  "info": {
    "title": "Tablefor API",
    "version": "1"
  },
  "paths": {
    "/__appbricx/api/v1/bookings": {
      "get": {
        "summary": "List bookings"
      }
    }
  }
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
404NO_APP"This project has no generated app yet."
curl
curl "$APP_ORIGIN/__appbricx/api/v1/openapi.json" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/openapi.json`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/queries-routes.ts:171

List rows

GET/__appbricx/api/v1/:table

A page of rows the caller may read, filtered and sorted in SQL.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:tablerequiredstringThe table name (an entity of the contract).

Query parameters

NameTypeDescription
limitoptionalnumberPage size (default 50, max 500).
offsetoptionalnumberRows to skip.
cursoroptionalstringOpaque cursor from a previous page. When present, offset is ignored and the answer carries nextCursor and hasMore.
whereoptionalJSON objectEquality filters, e.g. {"status":"open"}.
filteroptionalJSON arrayRich clauses [{ field, op, value }]. op: eq, neq, in, not_in, lt, lte, gt, gte, contains, not_contains, starts_with, ends_with, is_null, is_not_null, between, today, yesterday, this_week, this_month, this_year, last_n_days, next_n_days, range.
sortoptionalJSON object{"field":"created_at","dir":"desc"} (dir defaults to asc).

Response

With cursor: { ok, rows, rowCount, nextCursor, hasMore }.

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
400PARAMS_INVALIDwhere, filter or sort isn't valid JSON.
400(SQL error code)A filter names an unknown column or a value of the wrong type.
curl
curl "$APP_ORIGIN/__appbricx/api/v1/tickets?limit=20&where=%7B%22status%22%3A%22open%22%7D" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/tickets?limit=20&where=%7B%22status%22%3A%22open%22%7D`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedapp.queryuseEntityQuery

Source: services/api/src/app-runtime/http/queries-routes.ts:180

Aggregate

GET/__appbricx/api/v1/:table/aggregate

count, sum, avg, min or max over the matching rows, optionally per group or per day/week/month bucket, computed in SQL under the caller's row-level security.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:tablerequiredstringThe table name (an entity of the contract).

Query parameters

NameTypeDescription
metricrequired"count" | "sum" | "avg" | "min" | "max"What to compute.
columnoptionalstringThe column (required unless metric=count).
filteroptionalJSON arrayClauses as on list, including op "range".
rangeoptionalstringtoday, this_week, last_7_days, this_month, last_30_days, this_quarter, this_year or all.
dateFieldoptionalstringThe date column range applies to (default created_at).
tzoptionalIANA zoneTimezone for range and bucket (default UTC).
compareoptional"1"With range: also the previous period (both to date).
groupByoptionalstringOne value per distinct value of this column.
bucketoptional"day" | "week" | "month"With groupBy on a date column.

Response

With groupBy: { ok, groups: [{ key, value }], truncated? } (keys ascending, null last).

Response
{
  "ok": true,
  "value": 18420.5,
  "previous": 15210,
  "window": {
    "from": "2026-10-01",
    "to": "2026-10-12"
  },
  "previousWindow": {
    "from": "2026-09-01",
    "to": "2026-09-12"
  }
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
400PARAMS_INVALIDUnknown metric, or a column that doesn't exist on the table.
curl
curl "$APP_ORIGIN/__appbricx/api/v1/orders/aggregate?metric=sum&column=total&range=this_month&compare=1" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/orders/aggregate?metric=sum&column=total&range=this_month&compare=1`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

RelateduseAggregate

Source: services/api/src/app-runtime/http/queries-routes.ts:284

Get a row

GET/__appbricx/api/v1/:table/:id

One row by id. rows is empty when it doesn't exist or row-level security hides it.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:tablerequiredstringThe table name (an entity of the contract).
:idrequiredstringThe row id.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
curl
curl "$APP_ORIGIN/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedapp.getuseRecord

Source: services/api/src/app-runtime/http/queries-routes.ts:307

Create a row

POST/__appbricx/api/v1/:table

Insert a row. Owner columns are stamped from the caller's identity, before-write rules run, and a row-changed event fires (workflows on created).

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:tablerequiredstringThe table name (an entity of the contract).

Body

NameTypeDescription
(columns)requiredobjectThe row's own fields. Leave out id, owner columns and timestamps.

Response

201 Created.

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "priority": "high",
      "user_id": "u_42",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
403(stamp code)The caller may not write rows owned by someone else.
422RULE_REFUSEDA before-write rule refused the row; message says why.
409CONFLICTA unique constraint; the message is shown verbatim.
curl
curl -X POST "$APP_ORIGIN/__appbricx/api/v1/tickets" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION" \
  -H "content-type: application/json" \
  -d '{"title":"Printer jam","priority":"high"}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/tickets`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "title": "Printer jam",
    "priority": "high"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedapp.createGuides rules

Source: services/api/src/app-runtime/http/queries-routes.ts:330

Update a row

PATCH/__appbricx/api/v1/:table/:id

Patch a row. Before-write rules see the row as it would be. Lifecycle fields are refused here: use the transition endpoint.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:tablerequiredstringThe table name (an entity of the contract).
:idrequiredstringThe row id.

Body

NameTypeDescription
(columns)requiredobjectFields to change.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
422RULE_REFUSEDA before-write rule refused the change.
409E_LIFECYCLE_DIRECT_WRITEThe patch writes a lifecycle field.
409CONFLICTA unique constraint.
curl
curl -X PATCH "$APP_ORIGIN/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION" \
  -H "content-type: application/json" \
  -d '{"priority":"low"}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "priority": "low"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedapp.update

Source: services/api/src/app-runtime/http/queries-routes.ts:366

Delete a row

DELETE/__appbricx/api/v1/:table/:id

Delete a row the caller may delete.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:tablerequiredstringThe table name (an entity of the contract).
:idrequiredstringThe row id.

Response

Response
{
  "ok": true,
  "rows": [],
  "rowCount": 1,
  "fields": [],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
curl
curl -X DELETE "$APP_ORIGIN/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10`, {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedapp.remove

Source: services/api/src/app-runtime/http/queries-routes.ts:424

List external rows

GET/__appbricx/api/v1/ext/:entity

List rows of a table in an external Postgres database the builder connected. Same envelope and grammar as the tenant list, plus q for a case-insensitive search.

Auth
App key + signed-in user: Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION

Path parameters

NameTypeDescription
:entityrequiredstringA binding recorded on the project's connection (lowercase).

Query parameters

NameTypeDescription
limitoptionalnumberPage size (default 50, max 500).
offsetoptionalnumberRows to skip.
cursoroptionalstringOpaque cursor from a previous page. When present, offset is ignored and the answer carries nextCursor and hasMore.
whereoptionalJSON objectEquality filters, e.g. {"status":"open"}.
filteroptionalJSON arrayRich clauses [{ field, op, value }]. op: eq, neq, in, not_in, lt, lte, gt, gte, contains, not_contains, starts_with, ends_with, is_null, is_not_null, between, today, yesterday, this_week, this_month, this_year, last_n_days, next_n_days, range.
sortoptionalJSON object{"field":"created_at","dir":"desc"} (dir defaults to asc).
qoptionalstringILIKE search over the binding's text columns.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
401APP_SESSION_REQUIRED"Sign in to see this data." (no app session and no server key).
403TABLE_FORBIDDENThe role may not read this entity.
404EXTERNAL_ENTITY_UNKNOWNNot a binding of this project.
400PARAMS_INVALIDwhere, filter or sort isn't valid JSON.
502EXTERNAL_DB_ERRORThe external database failed (also AUTH_FAILED, UNREACHABLE); 504 TIMEOUT when it is too slow.

External databases have no row-level security that knows app users, so a signed-in, enabled app user (or a server key) is required and the access matrix applies per role.

curl
curl "$APP_ORIGIN/__appbricx/api/v1/ext/customers?limit=20&q=acme" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/ext/customers?limit=20&q=acme`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/external-routes.ts:103

Aggregate external rows

GET/__appbricx/api/v1/ext/:entity/aggregate

count, sum, avg, min or max over an external table's matching rows.

Auth
App key + signed-in user: Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION

Path parameters

NameTypeDescription
:entityrequiredstringThe binding.

Query parameters

NameTypeDescription
metricrequiredstringcount, sum, avg, min or max.
columnoptionalstringRequired unless count.
filteroptionalJSON arrayClauses.

Response

Response
{
  "ok": true,
  "value": 1284
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
401APP_SESSION_REQUIREDNo app session and no server key.
403TABLE_FORBIDDENRole may not read.
curl
curl "$APP_ORIGIN/__appbricx/api/v1/ext/customers/aggregate?metric=count" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/ext/customers/aggregate?metric=count`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/external-routes.ts:115

Get an external row

GET/__appbricx/api/v1/ext/:entity/:id

One external row by primary key.

Auth
App key + signed-in user: Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION

Path parameters

NameTypeDescription
:entityrequiredstringThe binding.
:idrequiredstringThe primary key value.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
401APP_SESSION_REQUIREDNo app session and no server key.
403TABLE_FORBIDDENRole may not read.
curl
curl "$APP_ORIGIN/__appbricx/api/v1/ext/customers/1042" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/ext/customers/1042`, {
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/external-routes.ts:133

Create an external row

POST/__appbricx/api/v1/ext/:entity

Insert into an external table. Refused on read-only bindings before any SQL runs.

Auth
App key + signed-in user: Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION

Path parameters

NameTypeDescription
:entityrequiredstringThe binding.

Body

NameTypeDescription
(columns)requiredobjectThe row.

Response

201 Created.

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
401APP_SESSION_REQUIREDNo app session and no server key.
405READ_ONLYThe binding is read-only.
403TABLE_FORBIDDENRole may not create.
409CONFLICTA unique value is taken.
curl
curl -X POST "$APP_ORIGIN/__appbricx/api/v1/ext/customers" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-app-session: $APP_SESSION" \
  -H "content-type: application/json" \
  -d '{"name":"Acme GmbH","country":"DE"}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/ext/customers`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-app-session": APP_SESSION,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "name": "Acme GmbH",
    "country": "DE"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/external-routes.ts:141

Update an external row

PATCH/__appbricx/api/v1/ext/:entity/:id

Patch an external row.

Auth
App key + signed-in user: Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION

Path parameters

NameTypeDescription
:entityrequiredstringThe binding.
:idrequiredstringThe primary key value.

Body

NameTypeDescription
(columns)requiredobjectFields to change.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam",
      "status": "open",
      "created_at": "2026-10-12T09:14:03Z"
    }
  ],
  "rowCount": 1,
  "fields": [
    {
      "name": "id",
      "type": "2950"
    },
    {
      "name": "title",
      "type": "25"
    }
  ],
  "truncated": false
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
401APP_SESSION_REQUIREDNo app session and no server key.
405READ_ONLYThe binding is read-only.
curl
curl -X PATCH "$APP_ORIGIN/__appbricx/api/v1/ext/customers/1042" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-app-session: $APP_SESSION" \
  -H "content-type: application/json" \
  -d '{"country":"AT"}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/ext/customers/1042`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-app-session": APP_SESSION,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "country": "AT"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/external-routes.ts:151

Delete an external row

DELETE/__appbricx/api/v1/ext/:entity/:id

Delete an external row.

Auth
App key + signed-in user: Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION

Path parameters

NameTypeDescription
:entityrequiredstringThe binding.
:idrequiredstringThe primary key value.

Response

Response
{
  "ok": true,
  "rows": [],
  "rowCount": 1
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
401APP_SESSION_REQUIREDNo app session and no server key.
405READ_ONLYThe binding is read-only.
curl
curl -X DELETE "$APP_ORIGIN/__appbricx/api/v1/ext/customers/1042" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-app-session: $APP_SESSION"
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/ext/customers/1042`, {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-app-session": APP_SESSION,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/app-runtime/http/external-routes.ts:161

Transition a lifecycle field

PATCH/__appbricx/api/v1/:entity/:id/transition

Move a lifecycle field along the contract's transition graph, checking the role restrictions on that edge.

Auth
App key + data marker: Authorization: Bearer $APP_KEYx-appbricx-data-api: 1x-appbricx-app-session: $APP_SESSION (optional: acts as that user)

Path parameters

NameTypeDescription
:entityrequiredstringThe table.
:idrequiredstringThe row id.

Body

NameTypeDescription
fieldrequiredstringThe lifecycle field, e.g. status.
torequiredstringThe target state.

Response

Response
{
  "ok": true,
  "from": "open",
  "to": "resolved"
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
400PARAMS_INVALIDThe x-appbricx-data-api: 1 header is missing.
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TABLE_FORBIDDENThe table isn't exposed, or the caller's role may not use this method on it.
400E_TRANSITION_INVALIDBody isn't { field, to }.
400E_FIELD_NOT_LIFECYCLEThe field has no lifecycle.
404E_ROW_NOT_FOUNDNo such row (or hidden).
404E_ENTITY_NOT_FOUNDUnknown entity.
409E_TRANSITION_FORBIDDENNo edge from the current state to `to`.
403E_TRANSITION_ROLEThe role may not make this move.
500E_TRANSITION_UPDATE_FAILEDThe write failed.
curl
curl -X PATCH "$APP_ORIGIN/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10/transition" \
  -H "Authorization: Bearer $APP_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "x-appbricx-app-session: $APP_SESSION" \
  -H "content-type: application/json" \
  -d '{"field":"status","to":"resolved"}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/api/v1/tickets/8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10/transition`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${APP_KEY}`,
    "x-appbricx-data-api": "1",
    "x-appbricx-app-session": APP_SESSION,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "field": "status",
    "to": "resolved"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Relatedapp.transition

Source: services/api/src/app-runtime/http/transition-routes.ts:38

Raw SQL: query

POST/__appbricx/data/query

Run one read statement with parameters on the tenant database. Browser apps use the CRUD API, named queries or search instead.

Auth
Server key: Authorization: Bearer $SERVER_KEYx-appbricx-data-api: 1

Body

NameTypeDescription
sqlrequiredstringOne statement with $1, $2… placeholders.
paramsoptionalunknown[]Placeholder values.

Response

Response
{
  "ok": true,
  "rows": [
    {
      "id": "8c1d…",
      "title": "Printer jam"
    }
  ],
  "rowCount": 1,
  "fields": [],
  "truncated": false,
  "elapsed_ms": 4
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
403ORIGIN_NOT_ALLOWEDA browser key used from an origin it isn't bound to (ORIGIN_REQUIRED when there is no Origin at all).
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403RAW_SQL_FORBIDDENNot a server-tier key.
403TOOL_NOT_ALLOWEDThe key's allowed tools exclude data.query.
400FORBIDDEN_STMTThe statement isn't a read.
403ADMIN_REQUIREDx-appbricx-admin without an admin session.
423WORKSPACE_QUARANTINEDThe workspace is under abuse review.
503WORKER_UNAVAILABLEThe project's database couldn't be reached.

x-appbricx-admin: 1 with an admin app session reads past row-level security.

curl
curl -X POST "$APP_ORIGIN/__appbricx/data/query" \
  -H "Authorization: Bearer $SERVER_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "content-type: application/json" \
  -d '{"sql":"select id, title from tickets where status = $1 limit 10","params":["open"]}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/data/query`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${SERVER_KEY}`,
    "x-appbricx-data-api": "1",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "sql": "select id, title from tickets where status = $1 limit 10",
    "params": [
      "open"
    ]
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/routes/app-data.ts:530

Raw SQL: exec

POST/__appbricx/data/exec

Execute a write statement with parameters. Emits change events for mutations.

Auth
Server key: Authorization: Bearer $SERVER_KEYx-appbricx-data-api: 1

Body

NameTypeDescription
sqlrequiredstringThe statement.
paramsoptionalunknown[]Placeholder values.

Response

Response
{
  "ok": true,
  "rows": [],
  "rowCount": 1,
  "fields": [],
  "truncated": false,
  "elapsed_ms": 6
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403RAW_SQL_FORBIDDENNot a server-tier key.
409QUOTA_EXCEEDEDThe workspace's storage quota is used up.
503WORKER_UNAVAILABLEThe database couldn't be reached.
curl
curl -X POST "$APP_ORIGIN/__appbricx/data/exec" \
  -H "Authorization: Bearer $SERVER_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "content-type: application/json" \
  -d '{"sql":"update tickets set status = 'closed' where id = $1","params":["8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10"]}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/data/exec`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${SERVER_KEY}`,
    "x-appbricx-data-api": "1",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "sql": "update tickets set status = 'closed' where id = $1",
    "params": [
      "8c1d2f9e-0d4b-4c39-9f63-2a1d5b7e8f10"
    ]
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/routes/app-data.ts:531

Raw SQL: schema

POST/__appbricx/data/schema

Introspect the tenant schema: tables, columns and keys.

Auth
Server key: Authorization: Bearer $SERVER_KEYx-appbricx-data-api: 1

Response

Response
{
  "ok": true,
  "tables": [
    {
      "name": "tickets",
      "columns": [
        {
          "name": "id",
          "type": "uuid",
          "nullable": false
        }
      ]
    }
  ],
  "elapsed_ms": 12
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TIER_INSUFFICIENTNot a server-tier key.
curl
curl -X POST "$APP_ORIGIN/__appbricx/data/schema" \
  -H "Authorization: Bearer $SERVER_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "content-type: application/json" \
  -d '{}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/data/schema`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${SERVER_KEY}`,
    "x-appbricx-data-api": "1",
    "content-type": "application/json",
  },
  body: JSON.stringify({}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/routes/app-data.ts:532

Raw SQL: migrate

POST/__appbricx/data/migrate

Apply a DDL migration once, recorded by id.

Auth
Server key: Authorization: Bearer $SERVER_KEYx-appbricx-data-api: 1

Body

NameTypeDescription
migration_idrequiredstringUnique id, ^[a-z0-9_-]{1,80}$.
sqlrequiredstringThe DDL.

Response

Response
{
  "ok": true,
  "applied": true,
  "elapsed_ms": 31
}

Errors

StatusCodeWhen
401UNAUTHORIZEDMissing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key").
429RATE_LIMITEDThe project's per-minute request budget is spent (600 for preview tokens and browser keys, 1200 for server keys by default).
403TIER_INSUFFICIENTDDL needs a server-tier key.
400PARAMS_INVALIDmigration_id missing or malformed.
curl
curl -X POST "$APP_ORIGIN/__appbricx/data/migrate" \
  -H "Authorization: Bearer $SERVER_KEY" \
  -H "x-appbricx-data-api: 1" \
  -H "content-type: application/json" \
  -d '{"migration_id":"add_ticket_sla","sql":"alter table tickets add column sla_hours int"}'
fetch
const res = await fetch(`${APP_ORIGIN}/__appbricx/data/migrate`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${SERVER_KEY}`,
    "x-appbricx-data-api": "1",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "migration_id": "add_ticket_sla",
    "sql": "alter table tickets add column sla_hours int"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);

Source: services/api/src/routes/app-data.ts:533

On this page

  1. Authentication
  2. Endpoints
  3. GET /queries
  4. POST /queries/*
  5. GET /api/v1/search
  6. GET /api/v1/openapi.json
  7. GET /api/v1/:table
  8. GET /api/v1/:table/aggregate
  9. GET /api/v1/:table/:id
  10. POST /api/v1/:table
  11. PATCH /api/v1/:table/:id
  12. DELETE /api/v1/:table/:id
  13. GET /api/v1/ext/:entity
  14. GET /api/v1/ext/:entity/aggregate
  15. GET /api/v1/ext/:entity/:id
  16. POST /api/v1/ext/:entity
  17. PATCH /api/v1/ext/:entity/:id
  18. DELETE /api/v1/ext/:entity/:id
  19. PATCH /api/v1/:entity/:id/transition
  20. POST /data/query
  21. POST /data/exec
  22. POST /data/schema
  23. POST /data/migrate
Appbricx

The backend, runtime and hosting for apps your coding agent builds. On our cloud, in yours, or on your own servers.

Features

Coding agents and MCPVerify testingBuilder consolePostgres databaseData APIRealtimeRow-level securitySign-in and authPaymentsWorkflows and jobsAI in your appIntegrationsBackups and rollbackHosting and domainsSelf-host and exportAll features

Product

ShowcasePricingFor coding agentsTemplatesPrivate cloudBring your own AI keyFAQ

Compare

Appbricx vs SupabaseLovable alternativeBolt alternativeFor freelancersFor agencies

Resources

DocumentationReferenceBlogSupportContact

© 2026 Appbricx. All rights reserved.

TermsPrivacyCookiesAcceptable Use