API reference

The Catentio control plane is a REST API that uses JSON for both requests and responses. It's the API the portal talks to, and these pages document its wire protocol: paths, params, object shapes, error bodies.

Read the reachability section first — there are two APIs here, and they are not the same surface.

Reachability

The public API is live at https://catent.io/v1/. It authenticates with an API key (Authorization: Bearer cat_pk_...) and is the surface you should build against.

It is small and deliberate: nine endpoints, listed below. It is not the same thing as the rest of this reference.

The public API — catent.io/v1/*

Nine endpoints, authenticated with an API key you create in the portal. This is what the SDKs, the CLI, and other Forjio products call.

Endpoint What it does
GET /v1/agents List the agents you can invoke (slug + description).
GET /v1/workflows List workflows, with the parameters each one declares as required.
POST /v1/runs Dispatch an agent run.
GET /v1/runs/{id} Status and output of a run.
POST /v1/projects Start a pipeline project from a workflow.
GET /v1/projects/{id} Status of a project.
POST /v1/webhooks Register a URL to be POSTed when runs/projects finish.
GET /v1/webhooks List your endpoints.
DELETE /v1/webhooks/{id} Delete an endpoint.

Anything not on that list returns 404 on catent.io/v1/. That is the design, not an omission: the public surface is an explicit allowlist, so an internal endpoint cannot be exposed by accident. See Authentication.

The control-plane API — everything else in this reference

The remaining pages document the internal control-plane protocol: the API the portal itself talks to. It is not public and is not reachable with an API key. Those paths are reached from a signed-in browser through the portal's proxy:

/api/v1/cp/<control-plane-path>

It reads your catentio_session cookie, forwards it to the control plane as the x-catentio-session header, and passes the response back. Without the cookie it returns 401 {"error":"auth_required"}. It does not accept Authorization: Bearer.

So GET /v1/runs in the control-plane sense is reached from a signed-in browser as GET /api/v1/cp/v1/runs — which is a different thing from the public GET /v1/runs above, even though the paths look alike. When in doubt: a cat_pk_ key talks to the public API; a browser session talks to the control plane.

Authentication

Credential Where it works
x-catentio-session header (portal cookie, HMAC-signed) Every control-plane route. This is the one the portal uses.
Authorization: Bearer <huudis-jwt> Only /v1/billing/*, /v1/chat/* (except /attachments and /call/turn), and /v1/workspaces list/get/create/delete.
Authorization: Bearer cat_pk_... (API key) Verified by the runtime, not by the control plane. See below.

Most routes accept the session header and nothing else. The Bearer-JWT path exists on a small set of routes for CLI/service callers.

API keys are a runtime credential. Keys minted at /v1/api-keys carry the prefix cat_pk_ and are checked by the agent runtime's auth guard — the control plane never looks at them. Scopes are not implemented: the scopes field is accepted and discarded, and a key grants full access to its customer's data.

A few routes are gated further: PATCH /v1/workspaces/{id}/state, /v1/crm-admin/* and GET /v1/customers are admin-only; /v1/gojo/* is internal-tenant-only.

See Authentication for the full picture.

Response shapes

There is no response envelope. The control plane returns plain FastAPI JSON.

List endpoints return a data array plus a per-route meta:

{
  "data": [ /* items */ ],
  "meta": { "total": 412, "limit": 50, "offset": 0 }
}

meta differs by route — the runs list carries {total, limit, offset}, the agents list carries {total, builtin, custom}. Detail endpoints return the object directly, with no wrapper.

Pagination is limit / offset. There are no cursors, no nextCursor, no hasMore.

Errors are FastAPI's detail body:

{ "detail": "auth_required" }

When the failure originated in the runtime, the control plane re-raises the runtime's status code and nests its payload:

{ "detail": { "code": "plan_limit_exceeded", "resource": "runs_per_day", "limit": 100, "tier": "free" } }

Validation failures are 422 with FastAPI's standard validation body. There is no error key, no requestId, and no timestamp on any response.

Resources

Resource Path prefix What it does
Workspaces /v1/workspaces Tenants.
Agents /v1/agents The agent roster + CRUD. (invoke is broken — see the page.)
Runs /v1/runs Start a run, list history, read events, cancel, retry.
Projects /v1/projects Pipeline-driven workflows: lifecycle, gates, backtrack.
Workflows /v1/workflows Versioned workflows — full CRUD.
Run artifacts /v1/run-artifacts Run outputs: recaps, comments, PIN-protected public sharing.
Tools /v1/tools The capability registry.
Skills /v1/skills Versioned agent playbooks.
Memory /v1/memory RAG entries (OTP-gated mutations).
API keys /v1/api-keys Static cat_pk_* credentials.
Billing /v1/billing Catalog, summary, subscribe, wallet, top-up.
Cost /v1/cost Workspace-level rollups.
Integrations /v1/integrations BYO credentials.
Webhook gates /v1/webhooks Inbound gates that block a pipeline step. List only.
Scheduled jobs /v1/scheduled-jobs Runtime cron.
Feature flags /v1/feature-flags Runtime kill switches.
Files /v1/files One route: GET /v1/files/download.
Output destinations /v1/output-destinations Where agent outputs go.
Heartbeats /v1/heartbeats Cron-triggered agent invocations.
System /v1/system Health, info, reload.
Chat /v1/chat The chat-bubble backend.
Events /v1/events Event archive feed.

Limits

There is no HTTP rate limiting: no per-second caps, no X-RateLimit-* headers, no 429, no Retry-After.

What can reject a request is a plan cap, enforced in the runtime and surfaced as 403:

Cap Free Starter Pro
Runs per day 100 5,000 unlimited

Custom agents, tools and skills carry per-tier count caps too. Over a cap you get 403 with a plan_limit_exceeded detail carrying resource, current, limit and tier.

There is no Idempotency-Key support. Retrying a POST /v1/runs spawns a second run.

Webhooks

There are two webhook features and they point in opposite directions. Do not confuse them.

OutboundWebhooks (outbound). Register a URL on the public API and Catentio POSTs to it when a run or project finishes. Three events (run.succeeded, run.failed, project.completed), HMAC-signed with X-Catentio-Signature: t=…,v1=…, retried with backoff. This is what you want if you'd rather not poll.

Inbound gatesWebhook gates. A pipeline step declared with a webhook gate blocks until an external system calls back to resolve it. GET /v1/webhooks (control plane) lists those gates.

There is no WebSocket and no SSE stream. The portal polls.

OpenAPI spec

There is no published OpenAPI file. The wire protocol's source of truth is the FastAPI route definitions — the control plane in saas-catentio (control_plane/app/routes/) and the agent runtime in catentio (app/runtime/). These reference pages are written against them.

Next

  • API authentication — what each credential actually opens.
  • Runs — start here; it's the resource everything else orbits.
  • Concepts — the data model the API exposes.