DocsAPI reference
§ reference · developers

API reference

Every Powerloom resource that you can model in YAML you can also create through the REST API. The REST surface is what weave (the CLI) and the console call; it's what you'll call from any application that needs to invoke an agent, list a fleet, or react to an audit event.

This page covers authentication, the resource shape, conventions across endpoints, and where to find the full machine-readable spec.


Where the spec lives

Powerloom serves OpenAPI 3.1 at /api/openapi.json (or https://api.powerloom.org/openapi.json against the cloud edition). That document is the source of truth — every endpoint, every body, every response shape is enumerated there. Generate clients from it, point Postman at it, hand it to your tooling of choice.

This page is the human-readable orientation. For the exhaustive endpoint list, the OpenAPI doc is faster to consume.


Authentication

Three ways to authenticate, in order of typical use:

JWT (browser, console)

The console issues a short-lived JWT after OIDC SSO or password+MFA. The token rides in the Authorization: Bearer <jwt> header. JWTs are user-scoped — every request resolves to your principal and your effective RBAC at the time.

JWTs expire in 30 minutes. The browser refreshes them silently via the refresh-token cookie; you don't see this. For machine-to-machine use, prefer a PAT.

Personal Access Tokens (CLI, automation)

Mint a PAT at /settings/access-tokens. The token format is pat_<43 char base64>. Copy it once at mint time — Powerloom only stores the SHA-256 hash. Revoke from the same page.

curl -H "Authorization: Bearer pat_xxxxxxxx..." \
  https://api.powerloom.org/me

PATs have the same RBAC as the user that minted them. Use sub-principals (next) when you want narrower scope per agent client.

Sub-principals (per-agent identities)

For per-AI-client identity (e.g., one identity for Claude Code, another for Codex CLI), mint a sub-principal at /settings/agents. Each sub-principal is a distinct principal_id in the audit log — you see "Shane via CC" vs "Shane via Codex" instead of just "Shane."

Sub-principals can optionally have narrowed permissions — RBAC is intersected against the parent user's RBAC. The user is the ceiling; the sub-principal can only restrict, never widen.

Token format: sub_<43 char base64>. Same Authorization: Bearer header.

Service accounts (CI, workload identity)

For org-owned non-human principals — CI runners, deploy bots, scheduled jobs — mint a Service Account at /organization/service-accounts. SA tokens look like sa_<43 char base64> and are governed by the same RBAC primitives as users.


Conventions

Base URL

Cloud: https://api.powerloom.org. Self-hosted: whatever your container is bound to (http://localhost:8000 for docker compose up defaults).

Content type

JSON for everything. Content-Type: application/json on requests with a body. Responses always set the header.

Pagination

List endpoints use ?limit= and ?cursor= (cursor-based; the response includes next_cursor when more pages are available).

GET /agents?limit=50&cursor=eyJpZCI6...

Default limit is 50. Max is 200.

Error shape

Every non-2xx response carries this body shape:

{
  "error": {
    "code": "rbac_denied",
    "message": "You do not have AgentAuthor at /acme/production.",
    "request_id": "req_01ABCDE..."
  }
}

code is machine-readable; message is human-readable. request_id matches the value in the X-Request-ID response header — quote it when filing a support issue.

Idempotency

Mutating endpoints accept an optional Idempotency-Key header. Same key + same body within 24h returns the original response without re-executing. Useful for retry-safe machine clients.


Resource endpoints

Every Kind in /docs/manifest-schema has a parallel REST surface:

KindListCreateReadUpdateDelete
OUGET /ousPOST /ousGET /ous/{id}PATCH /ous/{id}DELETE /ous/{id}
GroupGET /groupsPOST /groupsGET /groups/{id}PATCH /groups/{id}DELETE /groups/{id}
RoleBindingGET /role-bindingsPOST /role-bindingsGET /role-bindings/{id}DELETE /role-bindings/{id}
AgentGET /agentsPOST /agentsGET /agents/{id}PATCH /agents/{id}DELETE /agents/{id}
SkillGET /skillsPOST /skillsGET /skills/{id}PATCH /skills/{id}DELETE /skills/{id}
MCPDeploymentGET /mcp-deploymentsPOST /mcp-deploymentsGET /mcp-deployments/{id}PATCH /mcp-deployments/{id}DELETE /mcp-deployments/{id}
CredentialGET /credentialsPOST /credentialsGET /credentials/{id}DELETE /credentials/{id}

Role bindings and credentials don't expose PATCH — to change them, delete + recreate. This is intentional; it means the audit log captures discrete grant + revoke events instead of mutable rules that drift in meaning.


Agent invocation

The endpoint that does work, as opposed to the endpoints that govern who can do work.

POST /agents/{id}/invoke { "messages": [ {"role": "user", "content": "Summarize the latest support tickets."} ], "stream": false }

Response (non-streaming) carries the full assistant reply, the tool-use trace, and the session id for follow-up turns.

For streaming, set stream: true and consume the text/event-stream response — events are agent.text_delta, agent.tool_use_start, agent.tool_use_end, agent.complete. Same shape the console's chat surface consumes.

For a multi-turn conversation, pass session_id from the prior response on the next request — Powerloom stitches the turns together server-side, including memory retrieval and any approval-pending pauses.


Audit log

Every state-changing action lands in the audit log; you can query it.

GET /audit?action_verb=create&resource_kind=agent&since=2026-04-01

Filters: action_verb, resource_kind, resource_id, actor_principal_id, since, until. All optional; an unfiltered request returns the most recent 50 events.

For an export, GET /audit/export?format=csv returns a streaming CSV with the same filters applied. Large exports stream over many minutes — keep the connection open.


Notifications

The Phase 34 surface — list your unread, mark read, manage preferences, mint push subscriptions.

GET /me/notifications GET /me/notifications/unread-count POST /me/notifications/{id}/read GET /me/notification-preferences PUT /me/notification-preferences/{kind} POST /me/push-subscriptions GET /push/vapid-public-key # public, no auth

The notification stream GET /me/notifications/stream is server-sent events; consume with the standard EventSource API.


What this surface doesn't do

The REST API doesn't proxy LLM calls. When you POST /agents/{id}/invoke, Powerloom calls the upstream runtime (Anthropic by default) directly with your encrypted credential — we don't sit between you and Anthropic, we just govern who's allowed to make the call.

The REST API doesn't expose internal compliance machinery (audit chain hashing, work-chain events, reconciler internals) on the public surface. Those live behind the /_admin/ prefix and require super-admin auth, which is gated to the Powerloom-side super-admin team only.