Server & API

The Sixb server exposes a configured SixbHost through an Elysia HTTP + WebSocket API. It authenticates callers and enforces their grants across objects, telemetry, actions, automation runs, agents, and domain events under /api/* and /ws/*.

Reach for it whenever a browser front-end or another service needs to talk to your runtime over the network. The server serves the API only — the built-in admin UI (atlas) and any custom app run as separate servers that call it over HTTP.

Mental model

Sixb splits into three layers. The server is the middle one: it takes an already-built host and exposes its domain operations with authentication and authorization. It does not construct the host.

LayerYou callWhat it is
HostcreateSixb()Providers, definitions, and process lifecycle, in-process.
APIcreateSixbServer({ host, browser })Authorized HTTP + WebSocket access to domain operations.
Front-endsatlas + your appSeparate browser clients that call /api over HTTP.

Data flows one direction: front-ends → /api (cookies + CSRF) → server → runtime → storage, with domain events streaming back out over /ws/events.

Starting the server

The common path is sixb dev (runtime + atlas + custom app) or sixb api (API only). To embed the server directly:

TS
import { createSixb } from "@sixb/core"
import { createSixbServer } from "@sixb/server"

const host = await createSixb({ /* providers */ })

const server = createSixbServer({
  host,
  port: 3000,
  hostname: "0.0.0.0",
  browser: {
    publicOrigin: "https://api.acme.example",
    allowedOrigins: [
      { origin: "https://atlas.acme.example", audience: "atlas" },
      { origin: "https://app.acme.example", audience: "app" },
    ],
  },
})

await server.start()
// API at      http://0.0.0.0:3000
// OpenAPI at  http://0.0.0.0:3000/docs

await server.stop()

Options

OptionTypeDefaultDescription
hostSixbHost(required)A host from createSixb(). The server never builds one.
browserSixbApiBrowserPolicy(required)Origin policy: the API's publicOrigin and allowedOrigins.
portnumber3000TCP port to listen on.
hostnamestring"0.0.0.0"Bind hostname.
quietbooleanfalseSuppress startup logging.

The browser policy is load-bearing for security: it drives CORS, rejects disallowed Origin headers up front, and resolves the public origin used to mint auth redirects. Each allowedOrigins entry maps one front-end origin to its auth audience (atlas or app), and each audience can have only one origin. Configured audiences become invitation destinations and application-access boundaries.

Route groups

All JSON routes are prefixed with /api and mirror the runtime's typed APIs; see the linked pages for behavior. The full per-route request/response contract for objects lives in the HTTP reference.

GroupRepresentative routesSee
Objects CRUDGET /api/objects, GET/PUT /api/objects/:type/:idObjects
Object queryPOST /api/objects/query, .../query/count, .../query/exists, .../query/facetsQuerying
FilesPOST /api/files, /api/files/uploads/..., GET .../files/contentFiles
TelemetryGET/POST /api/objects/:type/:id/telemetry/:prop, .../history, .../latestTelemetry
LinksGET/PUT/DELETE /api/objects/:type/:id/links/:linkIdLinks
ActionsGET /api/actions, POST /api/actions/:actionIdActions
Action runsGET /api/action-runs, GET /api/action-runs/:runIdActions
OntologyGET /api/object-types, GET /api/object-types/:objectTypeIdOntology
Events (WS)GET /ws/eventsEvents
AgentsGET /api/agents, /api/agent-threads, .../messages, /api/agent-runs/:runId, GET /ws/agentsAgents
LogsGET /api/logs, GET /ws/logsLogging
WorkflowsGET /api/workflows, /api/workflow-runs, /api/workflows/:id/runsWorkflows
Interventions/api/workflow-interventions, .../:id/submit, .../:id/cancelInterventions
RulesGET /api/rules, GET /api/rule-statesRules
Datasets/api/datasets, .../versions, .../rowsDatasets
Syncs/api/syncs, /api/sync-runs, /api/syncs/:id/runsSyncs
Pipelines/api/pipelines, /api/pipeline-runs, /api/pipelines/:id/runsPipelines
ProjectionsGET /api/projections, GET /api/projections/:projectionIdProjections
ConnectorsGET /api/connectors, GET /api/connectors/:connectorIdConnectors
WebhooksPOST /api/webhooks/:connectorId/:webhookId, GET /api/webhook-runsConnectors
Auth/api/auth/session, /auth/sign-in, /auth/callback, /api/auth/...Auth
Project/StatusGET /api/project, GET /api/status, GET /health, GET /ready

Object data routes enforce the caller's grants: reads are filtered, and the object, link, and telemetry writes require edit:object or append:telemetry and answer 403 without it. File and auth-administration routes are authenticated-only — neither has a grant family yet. See Authorization.

Status endpoints have distinct meanings:

EndpointMeaningFailure behavior
GET /healthThe API process is alive.Returns 200 while the process can serve HTTP.
GET /readyStorage is reachable and its schema is current.Returns 503 when the runtime must leave traffic.
GET /api/statusCached outbox, retry, cleanup, and maintenance state.Reports degraded without removing a healthy API from traffic.

Files

A fileRef property holds a blob. Uploading it takes one request when the file is small, and a session when it is not.

RouteUse
POST /api/filesone multipart request; the whole file travels through the API
POST /api/files/uploadsopen a session for a large or client-uploaded file
PUT /api/files/uploads/:uploadId/contentsend the content through the API
POST /api/files/uploads/:uploadId/parts/:partNumberget a signed URL and upload the part directly to blob storage
POST /api/files/uploads/:uploadId/completefinish the session and get the reference
POST /api/files/uploads/:uploadId/abortdiscard it

Reading back is GET (or HEAD) on the owner's files/content, with a JSON pointer to the reference as path — on an object it must start with /properties:

BASH
curl "$API/api/objects/Invoice/inv-1/files/content?path=/properties/scan" -o scan.pdf

The same route shape hangs off action runs, workflow runs, workflow-run nodes, and agent thread messages — /api/action-runs/:runId/files/content, /api/workflow-runs/:runId/files/content, .../nodes/:nodeKey/files/content, and /api/agent-threads/:threadId/messages/:messageId/files/content.

Pre-0.1 limit — upload sessions are in-memory. Neither @sixb/pg nor @sixb/sqlite implements fileUploadSessions, so every session opened by POST /api/files/uploads lives in the serving process: it does not survive a restart and is not shared across replicas. Route a session's requests to one instance, supply your own store on host.storage.fileUploadSessions, or use single-request POST /api/files, which is unaffected.

Real-time events

GET /ws/events is a WebSocket stream of domain eventsobject.created, object.updated, telemetry.appended, link.created, action.requested, and more. Any authenticated principal may connect; each event is filtered per-principal by grants as it streams.

On connect, the server sends a connected control frame. Send a subscribe message to filter the stream — by topic (one domain-event topic such as objects, telemetry, links, or actions), types (specific event types), and/or objectTypeId (one object type) — and unsubscribe to stop:

JSON
{ "type": "subscribe", "topic": "objects", "types": ["object.created", "object.updated"], "objectTypeId": "Invoice", "limit": 100 }

The example above streams create and update events for Invoice objects only — useful for a billing dashboard that reacts as invoices are created, sent, or marked paid. The server replies with subscribed and unsubscribed control frames, streams matching events as { "type": "event", "event": ... }, and reports problems as { "type": "error", "message": ... }. For a typed client over this stream, see Client.

Two more WebSocket streams follow the same connect/subscribe shape: /ws/logs for run logs and /ws/agents for live agent runs.

OpenAPI

The server mounts Swagger UI at /docs and serves an OpenAPI document for every route group (tagged Objects, Telemetry, Actions, Workflows, Datasets, Syncs, Pipelines, Projections, Auth, and more). Zod schemas are converted to JSON Schema automatically, so the docs stay in sync with route validation. The generated typed client in packages/client is built from this contract — when routes or schemas change, run bun run generate:client.

Auth, CSRF, and cookies

Auth is enforced centrally. On every request the server resolves the session once and applies the caller's grants to protected domain operations. When auth is disabled explicitly, protected routes use that project configuration rather than bypassing authorization through a privileged runtime.

MechanismDetail
Session/auth/sign-in starts the flow; /auth/callback mints the httpOnly session cookie.
CSRFDouble-submit: a sixb_csrf cookie plus a matching x-sixb-csrf request header on mutations.
Browser originDisallowed Origin headers get a 403 before routing; CORS is restricted to allowedOrigins.

Browser front-ends call the API with credentials (cookies) and echo the CSRF token in the x-sixb-csrf header on writes. Server-to-server callers authenticate per your auth provider. See Authentication and Authorization for the full model.

Admin UI (atlas) vs custom apps

The API server serves no HTML. Front-ends are separate servers pointed at apiBaseUrl:

  • atlas — the built-in admin UI (@sixb/atlas). sixb dev starts it automatically alongside the API. It is a browser client for the same /api routes, scoped to the atlas audience.
  • custom app — your own front-end under the project's app directory, served with the app audience. See Apps.

Both are ordinary API clients. To build one, consume the typed Client and the Objects HTTP reference.

Search docs

Search the documentation