HTTP API¶
The UI uses the same API as any client. The interactive OpenAPI page is at
/docs on the API (http://localhost:8000/docs in development).
Services that only start workflows use the public API: see
Public API and SDKs and the
Public API reference (/openapi.public.json, /docs/public).
Envelope¶
Every REST response is an envelope:
// success
{"success": true, "data": <payload>, "error": null}
// error
{"success": false, "data": null, "error": {"code": "AUTH_INVALID_CREDENTIALS", "message": "Incorrect email or password", "details": null}}
code is stable UPPER_SNAKE and is the contract; message is English for
humans and logs. Clients translate by code and fall back to message. The
codes are listed in Error codes.
Workflow checks work the same way. POST /api/validate, saving a workflow
(POST /api/workflows) and using a template return errors, a list of English
messages, and issues, their codes in the same order: {"code", "params"}, or
null for a message without one. A run's error event over WebSocket carries
issues too when it reports these checks. The editor shows issues in the UI
language.
Authentication¶
| Client | How |
|---|---|
| API client | POST /api/auth/login → data.token; then Authorization: Bearer <token> |
| Browser | The studio_session cookie, plus X-Requested-With: studio on writes |
| WebSocket | The cookie, or ?token=<token> |
| Workflow trigger | Authorization: Bearer wft_… on /api/hooks/* and /api/lg/* only |
Running a workflow over WebSocket¶
WS /ws/run
→ {"workflow_id": "…", "input": {…}} start a saved workflow
→ {"resume_run_id": "…", "response": "approved"} answer a waiting Human node
→ {"workflow_id": "…", "workflow": {…}, …} run the editor's unsaved graph
→ {"workflow_id": "…", "input": {…}, "steps": 1} pause after one superstep
→ {"workflow_id": "…", "input": {…}, "until": "node_id"} pause after that node
→ {"type": "cancel"} cancel the current run
← {"type": "run_started", …} {"type": "node_started", …} {"type": "node_token", …}
{"type": "node_finished", …} … {"type": "run_finished", …}
Public Chat v1¶
All HTTP paths below are relative to /api/public/v1/chat/{slug} and appear
under tag Chat in the public OpenAPI
(/openapi.public.json, /docs/public on the server). The
socket guide links AsyncAPI and the frame schemas.
See Third-party auth and Compatibility.
| Method | Path | Result (data inside the JSON envelope) |
|---|---|---|
| GET | empty suffix | Page settings, access modes, steps mode and attachment limits |
| GET | /logo?v=<hash> |
Logo bytes, rather than an envelope |
| GET | /sessions |
{sessions:[...]}, only the caller's sessions |
| POST | /sessions |
New session; optional JSON {embed:true} |
| GET | /sessions/{sid} |
Session with turns and steps_mode |
| GET | /sessions/{sid}/turns?after=<turn_id> |
{turns:[...]} newer than this session's cursor; omit after for all |
| POST | /sessions/{sid}/attachments |
Uploaded file metadata; multipart field file |
| GET | /sessions/{sid}/attachments/{aid} |
Authenticated file download, bytes rather than an envelope |
| DELETE | /sessions/{sid}/attachments/{aid} |
{ok:true}; unsent files only |
| PUT | /sessions/{sid}/turns/{tid}/rating |
Rating; JSON {value:"up"} or {value:"down",comment?:"..."} |
| DELETE | /sessions/{sid}/turns/{tid}/rating |
{ok:true} |
Streaming: WS /ws/public/v1/chat/{slug} takes optional auth, then one
typed message or answer; cancel stops the active run. It emits typed
frames with v and seq. See Chat API for examples,
Human answers, persistence and reconnect behavior.
App users send an HS256 user JWT in HTTP Bearer or socket auth.token.
Anonymous same-origin clients use the chat cookie or X-Chat-Visitor
(auth.visitor / ?visitor= on the socket). X-Chat-Visitor: new requests
a new visitor token in data.visitor_token on session creation/listing.
Studio access uses the studio identity and stays same-origin. Cross-origin
clients need an app token and the key's allowed origin, without credentialed
CORS.
The unversioned HTTP /api/public/chat/{slug}/... paths are legacy aliases.
The old WS /ws/public/chat/{slug} remains same-origin with untyped frames.
GET /api/public/chat-frame?path=/c/{slug} is the iframe CSP check used by
nginx, not a session or streaming endpoint.
Endpoints¶
Auth and account
Workflows, versions, sharing
GET /api/workflows POST /api/workflows
GET /api/workflows/{wid} PATCH /api/workflows/{wid}
DELETE /api/workflows/{wid} POST /api/workflows/{wid}/duplicate
GET /api/workflows/{wid}/dependents POST /api/validate
GET /api/workflows/{wid}/versions GET /api/workflows/{wid}/versions/{n}
GET /api/workflows/{wid}/versions/diff POST /api/workflows/{wid}/versions/{n}/restore
GET /api/workflows/{wid}/shares PUT /api/workflows/{wid}/shares
DELETE /api/workflows/{wid}/shares/{target}
PUT /api/workflows/{wid}/team-shares DELETE /api/workflows/{wid}/team-shares/{tid}
GET /api/workflows/{wid}/transfer POST /api/workflows/{wid}/transfer
GET /api/workflows/{wid}/python (the code, node lines; ?version=n)
GET /api/workflows/{wid}/export/python (the .py file to download)
GET /api/workflows/{wid}/code (?language=python|typescript; same data as /python)
GET /api/workflows/{wid}/export/{language} (python: the .py file, typescript: the LangGraph.js .ts file)
GET /api/workflows/{wid}/export/{language}/project (the runnable LangGraph project zip for langgraph dev)
Runs
GET /api/workflows/{wid}/runs (?tests=true: test runs)
GET /api/runs/pending
GET /api/runs/{run_id} (one run with its events, as the history lists it; a workflow tool's child run)
GET /api/runs/{run_id}/checkpoints (time travel; fork: WS /ws/run {"fork": {...}})
POST /api/runs/{run_id}/cancel
WS /ws/run
API triggers and deliveries
GET /api/workflows/{wid}/tokens POST /api/workflows/{wid}/tokens
DELETE /api/workflows/{wid}/tokens/{tid} POST /api/workflows/{wid}/tokens/{tid}/rotate-secret
POST /api/hooks/workflows/{wid}/runs GET /api/hooks/workflows/{wid}/runs/{run_id}
GET /api/workflows/{wid}/deliveries POST /api/workflows/{wid}/deliveries/{did}/redeliver
GET /api/workflows/{wid}/mcp PUT /api/workflows/{wid}/mcp
POST /mcp (MCP Streamable HTTP, workflow token)
LangGraph Agent Server API (subset)
LangGraph-compatible API (guide), x-api-key: wft_… or a JWT.
GET /api/lg/info POST /api/lg/assistants/search
GET /api/lg/assistants/{id} GET /api/lg/assistants/{id}/graph
GET /api/lg/assistants/{id}/schemas POST /api/lg/threads
POST /api/lg/threads/search GET /api/lg/threads/{tid}
DELETE /api/lg/threads/{tid} GET /api/lg/threads/{tid}/state
POST /api/lg/threads/{tid}/history POST /api/lg/threads/{tid}/runs
POST /api/lg/threads/{tid}/runs/wait POST /api/lg/threads/{tid}/runs/stream
GET /api/lg/threads/{tid}/runs GET /api/lg/threads/{tid}/runs/{rid}
GET /api/lg/threads/{tid}/runs/{rid}/join POST /api/lg/threads/{tid}/runs/{rid}/cancel
POST /api/lg/runs POST /api/lg/runs/wait
POST /api/lg/runs/stream
Schedules
Chat triggers
Chat and the public chat page
GET /api/workflows/{wid}/chat PUT /api/workflows/{wid}/chat (settings; PUT needs owner access)
GET /api/workflows/{wid}/chat/sessions POST /api/workflows/{wid}/chat/sessions
GET /api/chat/sessions/{sid}?view=builder|visitor DELETE /api/chat/sessions/{sid}
GET /api/workflows/{wid}/chat/visitors GET /api/workflows/{wid}/chat/visitors/{sid} (read-only)
GET /api/workflows/{wid}/chat/logo?v= (logo: a data: URL in PUT sets it, "" removes it)
GET /api/workflows/{wid}/chat/app-keys POST /api/workflows/{wid}/chat/app-keys
DELETE /api/workflows/{wid}/chat/app-keys/{key_id} (owner/admin; one-time secret on creation)
WS /ws/run {chat_session_id, message} | {chat_session_id, resume_run_id, response}
Legacy public HTTP aliases (authentication depends on the chat's access modes):
New clients use the complete Public Chat v1 section above.
GET /api/public/chat/{slug} (title, intro, suggestions, access, steps_mode, signed_in, embed_origins, logo)
GET /api/public/chat/{slug}/sessions POST /api/public/chat/{slug}/sessions ({embed?})
GET /api/public/chat/{slug}/sessions/{sid}
GET /api/public/chat/{slug}/sessions/{sid}/turns?after=<turn_id> (only the newer turns)
GET /api/public/chat/{slug}/logo?v=<logo>
WS /ws/public/chat/{slug} {chat_session_id, message} | {chat_session_id, response}
WS /ws/public/v1/chat/{slug} the socket protocol v1: typed frames with v and seq (AsyncAPI: /asyncapi.public.yaml)
GET /api/public/chat-frame?path=/c/{slug} (its frame-ancestors, for nginx)
An anonymous visitor is an HttpOnly cookie, or the X-Chat-Visitor header
(?visitor= on the socket) in an embed. Send X-Chat-Visitor: new to get a
token back as visitor_token.
Workflow tests
GET /api/workflows/{wid}/tests POST /api/workflows/{wid}/tests
PUT /api/workflows/{wid}/tests/{tid} DELETE /api/workflows/{wid}/tests/{tid}
POST /api/workflows/{wid}/tests/run ({test_ids?, mock?, version?}: version = a stored earlier version)
GET /api/workflows/{wid}/tests/runs (suite history)
GET /api/workflows/{wid}/tests/runs/{sid} (with the comparison to an earlier version)
POST /api/workflows/{wid}/tests/runs/{sid}/cancel
POST /api/workflows/{wid}/tests/runs/{sid}/langsmith
POST /api/workflows/{wid}/tests/from-run/{run_id} (a draft case from a run, not saved)
Templates
Credentials and providers
Knowledge bases
GET /api/knowledge-bases POST /api/knowledge-bases
GET /api/knowledge-bases/{kid} PUT /api/knowledge-bases/{kid}
DELETE /api/knowledge-bases/{kid} POST /api/knowledge-bases/{kid}/documents
DELETE /api/knowledge-bases/{kid}/documents/{did}
POST /api/knowledge-bases/{kid}/reindex POST /api/knowledge-bases/{kid}/search
MCP servers
Approvals and identities
GET /api/approvals/channels POST /api/approvals/channels
PUT /api/approvals/channels/{cid} DELETE /api/approvals/channels/{cid}
POST /api/approvals/channels/{cid}/test POST /api/approvals/channels/{cid}/register-webhook
POST /api/approvals/callback/{kind} GET|POST /api/approvals/callback/{kind}/{cid}
POST /api/channels/events/slack (Slack Events API: chat triggers; Telegram messages use the callback URL)
GET /api/approvals/identities PUT /api/approvals/identities
POST /api/approvals/identities/{kind}/send-code
POST /api/approvals/identities/{kind}/verify
GET /api/approvals/link POST /api/approvals/link
GET /api/approvals/audit
GET /api/approvals/inbox POST /api/approvals/inbox/{run_id}
GET /api/approvals/slack/oauth POST /api/approvals/slack/oauth/start
GET /api/approvals/slack/oauth/callback
Notifications
Users, teams, administration
GET /api/roles
GET /api/admin/users PATCH /api/admin/users/{target}
DELETE /api/admin/users/{target} POST /api/admin/users/{target}/password-reset
GET /api/admin/policy PUT /api/admin/policy
GET /api/admin/langsmith PUT /api/admin/langsmith
GET /api/admin/audit
GET /api/teams POST /api/teams
PATCH /api/teams/{tid} DELETE /api/teams/{tid}
POST /api/teams/{tid}/members DELETE /api/teams/{tid}/members/{member}