API reference
Two surfaces, two credentials, two hosts.
| Surface | Host | Auth | For |
|---|---|---|---|
| Control plane | https://oberik.com | X-API-Key: pk_… | administering a project — Project API |
| Data plane | https://api.oberik.com | Authorization: Bearer <jwt> | everything an end-user does |
The SDK has a client for each, and they are separate types because their credentials
are: createClient takes an end-user token and runs wherever your app runs;
createProjectClient holds the project key and runs only on your server.
import { createClient, createProjectClient } from "@oberik/sdk";
// Server-side: administers the project and mints tokens.
const oberik = createProjectClient({ projectId, projectKey });
// Anywhere: one end-user's view of the data plane.
const ai = createClient({ getToken: oberik.tokens.forUser({ subject: user.id }) });
createClient already knows where the data plane is, so baseUrl is only needed
for a self-hosted deployment or local development:
import { createClient } from "@oberik/sdk";
const ai = createClient({
// Recommended: called for a token, and again with { expired: true } on a 401.
getToken: async ({ expired }) => fetchTokenFromYourBackend({ force: expired }),
// baseUrl: "http://localhost:8000", // only if you're not on the hosted API
});
The data plane also serves its own generated OpenAPI schema —
/openapi.json, with an interactive explorer at
/docs on the API host (not on this site). That schema is generated from the running
code, so it is the authority on request and response shapes; this page is the map.
Control plane
Authenticated with X-API-Key. The key is project admin, not just a minting
credential — see the warning.
| Method | Path | Purpose |
|---|---|---|
POST | /api/projects/:id/token | mint an end-user JWT |
GET | /api/projects/:id | the project, with its capability ceiling |
PATCH | /api/projects/:id | rename, or change the ceiling ({ capabilities: {…} }) |
GET | /api/projects/:id/capabilities | the ceiling alone, every flag present, plus supported modalities |
PUT | /api/projects/:id/system-prompt | the project's system prompt |
PUT | /api/projects/:id/origins | browser origins allowed to call the API |
GET POST DELETE | /api/projects/:id/keys[/:keyId] | project API keys (created ones are shown once) |
GET POST DELETE | /api/projects/:id/documents[/:documentId] | the project-owned corpus |
GET POST | /api/projects/:id/skills | this project's skills — including end-users' own private uploads, which visibility and owner_subject tell apart |
DELETE | /api/projects/:id/skills/:pluginId | remove one |
GET POST DELETE | /api/projects/:id/mcp[/:mcpId] | the project's MCP servers |
GET POST DELETE | /api/projects/:id/webhook-tools[/:toolId] | tools the agent calls by URL (the signing secret is returned once) |
POST | /api/projects/:id/webhook-tools/:toolId/rotate | a new signing secret; the old one keeps verifying for 24 hours |
GET | /api/projects/:id/webhook-tools/deliveries | recent calls to your handlers — when, which tool, what came back |
GET POST DELETE | /api/projects/:id/providers[/:credId] | your own LLM keys |
POST | /api/projects/:id/providers/:credId/refresh | re-read a provider's catalog and prices |
GET POST | /api/projects/:id/default-model | model used when a request names none |
PUT | /api/projects/:id/retrieval | embedding and rerank overrides |
PUT | /api/projects/:id/document-processor | how documents are read |
PUT | /api/projects/:id/guardrails | oberik.guardrails.set — input and output checks |
PUT | /api/projects/:id/subagents | oberik.subagents.set — which models delegates may run on |
PUT | /api/projects/:id/citations | oberik.citations — inline markers or a source list |
POST | /api/projects/:id/retrieval/probe | oberik.retrieval.probe — measure an embedding model's dimension |
GET | /api/projects/:id/context | context-window strategy |
GET | /api/projects/:id/usage · /observability | spend, requests, tokens, latency, per-model and per-user |
GET | /api/projects/:id/limits | usage caps on the project's LLM key |
GET | /api/projects/:id/sessions[/:sessionId/messages] | every session in the project — subagents' own excluded unless include_subagents |
GET | /api/projects/:id/readiness | oberik.readiness — what still has to happen before this project can answer |
GET | /api/projects/:id/connect | oberik.connect — the starting snippet and this project's endpoints |
GET POST | /api/projects/:id/webhook-secret[/rotate] | the key that signs deliveries to you |
GET | /api/projects/:id/tasks | scheduled tasks |
GET DELETE | /api/projects/:id/wiki[/:itemId] | what the agent has written |
GET | /api/projects/:id/sandboxes · /sandbox-host | live sandboxes, and what they provide |
POST | /api/projects/:id/sandboxes/:sessionId/:action | pause · resume · delete |
GET PUT | /api/projects/:id/computer | oberik.computer — this project's own command timeout and how many sandboxes it may hold |
GET | /api/orgs/:orgId/projects · /costs | across the organization — session only, not a project key |
Creating a project (POST /api/orgs/:orgId/projects) and its first key need a signed-in
account rather than a key, so those two steps happen in the dashboard.
POST /api/projects/:id/token
| Field | Type | Meaning |
|---|---|---|
subject | string | who the token is (hierarchical identity path) |
scope | string | visibility boundary — a prefix of subject |
capabilities | string[] | intersected with the project's ceiling |
roles, groups | string[] | added to the project's defaults; used by document ACLs |
models | string[] | model allow-list |
maxEffort | enum | minimal | low | medium | high |
maxToolIterations | number | agent↔tool loop ceiling (default: unlimited) |
maxContextTokens | number | history ceiling for this token, clamped against the project's |
expiresIn | number | TTL in seconds (default 3600) |
Returns { access_token, token_type, expires_in, tenant_id, capabilities, scope, allowed_models, max_effort, max_context_tokens }.
capabilities is what was actually granted — compare it with what you asked for to see
what the ceiling trimmed.
Data plane
Chat
| Method | Path | SDK |
|---|---|---|
POST | /chat | ai.chat.send · ai.chat.run |
POST | /chat/stream | ai.chat.stream |
GET | /chat/stream/{run_id} | resume (automatic) |
POST | /chat/stream/{run_id}/cancel | handle.cancel() |
POST | /chat/stream/{run_id}/steer | handle.steer · ai.chat.steer |
GET | /chat/sessions | ai.chat.sessions.list — subagents' own conversations excluded unless include_subagents |
GET | /chat/sessions/{id}/messages | ai.chat.sessions.messages |
GET | /chat/sessions/{id}/todos | ai.chat.sessions.todos |
GET | /chat/sessions/{id}/events | ai.chat.sessions.watch |
POST | /chat/sessions/{id}/followups | ai.chat.sessions.followups |
POST | /chat/sessions/{id}/recap | ai.chat.sessions.recap |
POST | /chat/sessions/{id}/fork | ai.chat.sessions.fork |
DELETE | /chat/sessions/{id} | ai.chat.sessions.delete |
Answering a paused question is ai.chat.answer — a POST /chat carrying
question_answers, not its own endpoint. Approving a paused action is the same shape
with approval_decisions, and returning client-tool results is tool_results.
Browser hand-off
| Method | Path | SDK |
|---|---|---|
POST | /chat/sessions/{id}/browser/frame | ai.chat.sessions.browserFrame |
GET | /chat/sessions/{id}/browser/stream | ai.chat.sessions.browserStream (SSE screencast) |
POST | /chat/sessions/{id}/browser/input | ai.chat.sessions.browserInput |
POST | /chat/sessions/{id}/browser/check | ai.chat.sessions.handoffCheck |
ai.chat.sessions.handoff() wraps all four into one controller — Handing the page to
the user.
Documents
| Method | Path | SDK |
|---|---|---|
POST | /documents | ai.documents.uploadSimple |
GET | /documents | ai.documents.list |
GET | /documents/{id} | ai.documents.get |
PATCH | /documents/{id} | ai.documents.update |
POST | /documents/{id}/reingest | ai.documents.reingest |
GET | /documents/{id}/chunks | ai.documents.chunks |
GET | /documents/{id}/download-url | ai.documents.downloadUrl |
DELETE | /documents/{id} | ai.documents.delete |
POST | /documents/retrieve | ai.documents.retrieve |
POST | /documents/presign-upload | ai.documents.upload |
POST | /documents/{id}/presign-parts | ″ |
POST | /documents/{id}/complete-upload | ″ |
POST | /documents/{id}/abort-upload | ″ |
Tools, tasks, triggers
| Method | Path | SDK |
|---|---|---|
GET | /tools | ai.tools.list |
GET | /capabilities | ai.capabilities — what this token holds, and which enable_* switches are worth setting on it |
POST | /tasks | ai.tasks.create |
GET | /tasks · /tasks/{id} | ai.tasks.list · ai.tasks.get |
POST | /tasks/{id}/cancel | ai.tasks.cancel |
POST GET | /triggers | ai.triggers.create · ai.triggers.list |
POST | /triggers/{trigger_id}/rotate | ai.triggers.rotate — new URL, old one alive 24h |
DELETE | /triggers/{trigger_id} | ai.triggers.delete |
POST | /triggers/{slug} | fire one — no bearer token; the URL is the credential |
Skills and memory
| Method | Path | SDK |
|---|---|---|
POST | /plugins | ai.plugins.upload · ai.plugins.uploadFolder |
GET | /plugins | ai.plugins.list |
DELETE | /plugins/{id} | ai.plugins.delete |
GET | /memory | ai.memory.list — what the agent remembers, and its wiki pages |
DELETE | /memory/{item_id} | ai.memory.delete |
Sandboxes
| Method | Path | SDK |
|---|---|---|
GET | /computers/host | ai.computers.host |
POST GET | /computers/sessions | ai.computers.create · list |
GET DELETE | /computers/sessions/{id} | ai.computers.get · destroy |
POST | /computers/sessions/{id}/pause · /resume | ai.computers.pause · resume |
POST | /computers/sessions/{id}/exec | ai.computers.exec |
POST GET | /computers/sessions/{id}/files | ai.computers.upload · download |
Governance
| Method | Path | SDK |
|---|---|---|
GET | /audit | ai.audit.list |
POST | /audit/forget | ai.audit.forget |
POST | /auth/token | ai.auth.token — narrow an existing credential |
GET | /health · /ready | ai.health.live · ai.health.ready |
/tenants exists too, for a service key provisioning tenants directly — including
DELETE /tenants/{id}, which erases a tenant whole: every row carrying its id, its vectors,
its raw bytes in object storage, its sandboxes and its schedules. An integration using
projects never touches it; deleting a project calls
it for you.
Capabilities
The complete set, grouped as the dashboard groups them, with the per-request flag that can decline each one. Fuller descriptions, and what a token can and can't do with them, are in Authentication.
| Group | Capabilities | Per-request flags |
|---|---|---|
| Conversation | chat, system_prompt, steer, voice | enable_voice_control |
| Knowledge | documents:read, documents:write, memory | enable_rag, enable_memory |
| Internet | web_search, browser, browser_handoff | enable_web_search, enable_browser |
| Agentic | todo, computer, subagents, tasks:read, tasks:write, triggers | enable_todo, enable_computer, enable_subagents, enable_scheduling |
| Human in the loop | ask_user, approvals, ui_tools, followups, recap, auto_title, voice:transfer | enable_ask_user, enable_approvals, enable_auto_title |
| Extensions | webhook_tools, mcp:manage, plugins:write, action_space | enable_webhook_tools, enable_plugins, enable_action_space |
| In and out | input:file (accept any upload) · input:image|audio|video (model perceives it directly) · output:file (send any produced file) · output:image|audio|video (model generates it) | output_modalities |
The effective answer for any tool family is always project ceiling ∩ token capability ∩
per-request flag, plus allowed_tools if you set one. A client can always decline; it
can never exceed.
For agents
This documentation is published in machine-readable form:
llms.txt— the indexllms-full.txt— every page, one fileapi.oberik.com/openapi.json— the data plane's own schema, generated from the running code