Skip to main content

REST API conventions

Everything on this page applies to every endpoint in this section.

Base URL

All API routes (except /ping) are prefixed with /v1/.

Response envelope

Every successful endpoint wraps its payload in a uniform envelope:

{
"success": true,
"data": { ... },
"message": "optional message",
"timestamp": "2026-05-23T10:00:00Z"
}

Errors (4xx / 5xx) return FastAPI's standard detail format:

{
"detail": "Not authorized to invoke graph"
}

Authentication

When auth is configured in agentflow.json, all endpoints except /ping require a Bearer token:

Authorization: Bearer <token>

WebSocket connections that cannot set an Authorization header have two options, in order of preference:

// Preferred for browsers: the token rides in a request header, not the URL
new WebSocket("ws://host/v1/graph/ws", ["agentflow-bearer", token]);
# Last-resort fallback: the token lands in URLs and access logs
/v1/graph/ws?token=<token>

The server echoes the agentflow-bearer sentinel back on accept(), which browsers require to complete the handshake.

If auth is not configured ("auth": null), credentials are not required and the auth layer is skipped entirely.

Authentication failures return HTTP 403 with an error.code such as REVOKED_TOKEN or EXPIRED_TOKEN, not 401. On WebSocket routes the same failures become close code 1008.

Permission model

Each endpoint requires a specific (resource, action) pair. The table below lists them. When an AuthorizationBackend is configured, the authorize(user, resource, action) method is called. The built-in DefaultAuthorizationBackend allows all requests as long as user_id is present.


Permission reference

The table below lists every (resource, action) pair enforced by the server. When an AuthorizationBackend is configured, each request calls authorize(user, resource, action).

EndpointResourceAction
POST /v1/graph/invokegraphinvoke
POST /v1/graph/streamgraphstream
WebSocket /v1/graph/wsgraphstream
WebSocket /v1/graph/livegraphstream
GET /v1/graphgraphread
GET /v1/graph/toolsgraphread
GET /v1/observability/{thread_id}graphread
GET /v1/graph:StateSchemagraphread
POST /v1/graph/stopgraphstop
POST /v1/graph/setupgraphsetup
POST /v1/graph/fixgraphfix
GET /v1/threads/{id}/statecheckpointerread
PUT /v1/threads/{id}/statecheckpointerwrite
DELETE /v1/threads/{id}/statecheckpointerdelete
GET /v1/threads/{id}/messagescheckpointerread
GET /v1/threads/{id}/messages/{msg}checkpointerread
POST /v1/threads/{id}/messagescheckpointerwrite
DELETE /v1/threads/{id}/messages/{msg}checkpointerdelete
GET /v1/threadscheckpointerread
GET /v1/threads/{id}checkpointerread
DELETE /v1/threads/{id}checkpointerdelete
POST /v1/store/memoriesstorewrite
POST /v1/store/searchstoreread
POST /v1/store/memories/{id}storeread
POST /v1/store/memories/liststoreread
PUT /v1/store/memories/{id}storewrite
DELETE /v1/store/memories/{id}storedelete
POST /v1/store/memories/forgetstoredelete
POST /v1/files/uploadfilesupload
GET /v1/files/{id}filesread
GET /v1/files/{id}/infofilesread
GET /v1/files/{id}/urlfilesread
GET /v1/config/multimodalconfigread
GET /ping(none)(none)
GET /v1/evals/runs(none)(none)
GET /v1/evals/runs/{run_id}(none)(none)

The last three rows are the complete public allowlist. Every other route must carry a RequirePermission guard, and the server refuses to start if one does not.

The eval endpoints are unauthenticated

/v1/evals/runs* serves the contents of eval_reports/ to anyone who can reach the port, regardless of your auth setting. Keep eval_reports/ out of the deployed working directory, or block /v1/evals/* at your ingress. See eval endpoints.


HTTP status codes

CodeWhen
200Success
400Empty file upload or missing required field
401Token missing or invalid (when auth is configured)
403Authorization check failed
404Resource not found (file, thread, message)
413Uploaded file exceeds MEDIA_MAX_SIZE_MB
422Request validation error (malformed body or invalid param)
500Unexpected server error