Reference

REST API

The HTTP surface ObjectOS generates from your metadata — where the product uses it, a few examples, and the full specification on objectstack.ai.

Full specification: REST and GraphQL APIs on objectstack.ai. This page is the summary: where ObjectOS uses it, and a few examples.

Every object you declare gets REST endpoints, every action becomes a POST, and every flow can be started over HTTP. There is no separate API layer to write or deploy. The base URL is https://<your-host>/api/v1, and the running runtime describes itself at /api/v1/openapi.json (OpenAPI 3.0) and at /api/v1 (service discovery).

Every route under /api/v1 needs a signed-in session or a bearer token unless a declaration opens it to anonymous callers, as public forms and share links do. Permissions are checked per route and per record: object-, record- and field-level security apply to an API caller exactly as they apply in the UI. See API Access for keys and tokens.

Where ObjectOS uses it

SurfaceRoutesUsed by
Data/data/:object, /data/:object/:id, /data/:object/queryThe generated UI, your integrations, imports and exports — queries are ObjectQL
Actions/actions/:object/:actionButtons in the UI, and agents when the action is exposed to AI (Actions)
Automation/automation/:name/trigger, /automation/:name/runsStarting a flow from another system, and reading its runs (Flows)
Metadata/meta/:type/:nameStudio, which saves through it, and tooling that reads the running metadata
AI/ai/chat, /ai/pending-actionsThe AI Builder and its approval queue
Public forms/forms/:slugA form view published for anonymous respondents

Examples

List open tickets, newest first:

GET /api/v1/data/support_ticket?where={"status":{"$eq":"open"}}&orderBy=-created_at&limit=20
Authorization: Bearer <token>
{
  "object": "support_ticket",
  "records": [ { "id": "...", "subject": "...", "status": "open" } ],
  "total": 137,
  "hasMore": true
}

Take an object off the API, or make it read-only, in its enable block:

import { ObjectSchema, Field } from '@objectstack/spec/data';

// A read-only reference object, never writable over the API:
ObjectSchema.create({
  name: 'exchange_rate',
  enable: { apiMethods: ['get', 'list'] },
  fields: {
    rate: Field.number({ label: 'Rate', scale: 6 }),
    // ...more fields
  },
})

// An internal object that the API never exposes:
ObjectSchema.create({
  name: 'sync_cursor',
  enable: { apiEnabled: false },
  fields: {
    cursor: Field.text({ label: 'Cursor' }),
    // ...more fields
  },
})

Branch on the error code, never on the message:

{
  "error": {
    "code": "PERMISSION_DENIED",
    "message": "Missing ai:approve on conversation 01H…",
    "httpStatus": 403,
    "details": { "permission": "ai:approve", "subject": "01H…" }
  }
}

Restricting the API surface

An object's enable block governs its generated endpoints. apiEnabled: false omits the object from the REST surface entirely, so its routes answer 404. apiMethods is a whitelist of get, list, create, update, delete and bulk; any other operation is refused at the REST layer. Both are enforced (ADR-0049); earlier versions parsed them without applying them.

Public forms

Answered without a session. A form view opts in through its sharing, and all three keys are required: enabled: true, allowAnonymous: true and a publicLink slug. Since ObjectStack 17.7 a form that sets only the last two answers 404 FORM_NOT_FOUND — see Views → Public forms. GET /forms/:slug returns the form, POST /forms/:slug/submit submits it.

Also answered without a session: the token in the link is the authorization. GET /share-links/:token/resolve returns the one record the link shares, without the fields the link hides. A link limited to signed-in users answers 401 SIGN_IN_REQUIRED to a caller without a session, and a password-protected one answers 401 NEEDS_PASSWORD until the password is sent. Creating, listing and revoking links (POST /share-links, GET /share-links, DELETE /share-links/:idOrToken) need a session — see Share links: anyone with the link.

Flow status table

The trigger route, an action of type flow and a declared type: 'flow' endpoint all answer the same statuses. Branch on the HTTP status, not on a success flag inside the body:

StatusCodeMeans
200—The run dispatched. Its status is completed, paused (it waits on a screen, an approval or a timer), or refused (it reached an end node with outcome: 'refused'; the text is in refusalMessage)
404RESOURCE_NOT_FOUNDNo flow has that name
409FLOW_DISABLEDThe flow is switched off
422FLOW_NO_START_NODEThe stored definition has no start node and cannot run
400FLOW_FAILEDThe run dispatched and failed; the details carry the flow's errorMessage

Metadata — /api/v1/meta/*

/meta/:type/:name is the only address of a metadata item; percent-encode a name that carries a slash (GET /api/v1/meta/lead/views%2Fall_leads). The sectioned /meta/:type/:section/:name routes were retired in ObjectStack 17.3 and answer 404 ROUTE_NOT_FOUND. Saving needs an authoring capability, and reading or saving datasource metadata needs manage_platform_settings.

Reports

There is no saved-report API. ObjectStack 17.5 removed /reports, /reports/:id/run and /reports/:id/schedule, which now answer 404. A report is metadata, read through /meta/report/:name, and its numbers come from analytics (POST /analytics/query).

See also

  • API Access — keys, tokens and who may call what
  • ObjectQL — the query format /data/* accepts
  • Security — what every route checks before it runs