Skip to content

HTTP API

Everything the web app and the CLI do goes through LangAlpha’s HTTP API, and you can call it from your own code. This page covers how the API behaves in general. A full endpoint reference is coming; until then, the CLI’s source is a compact, working example of the routes most people need.

Every route lives under /api/v1 on your LangAlpha server, for example http://localhost:8000/api/v1/threads on a default self-hosted install.

Requests and responses are JSON. An error comes back with an HTTP status and a detail field, which is one of:

  • a sentence, such as {"detail": "Thread not found"};
  • an object with a message and a machine-readable type or code, such as insufficient_scope;
  • for a request that does not validate (422), a list of the problems found.
Status Meaning
400, 422 The request is invalid.
401 No credential, or one the server refuses.
403 The credential may not do this.
404 Not found.
409 A conflict with the current state, such as answering a thread that is waiting for nothing.
429 Too many requests; the Retry-After header says how many seconds to wait.
503 The server cannot answer right now; retry after Retry-After when it is set.

Sending a message runs a turn, and the response is a stream of server-sent events (text/event-stream) that lasts as long as the turn:

  • POST /api/v1/threads/messages starts a new thread. The body names a workspace_id and messages, a list holding one {"role": "user", "content": "..."}, and optionally an llm_model.
  • POST /api/v1/threads/{thread_id}/messages sends to an existing thread. If a turn is running there, the message steers it.

Each event has a name, a numbered id, and JSON data. Among the first is metadata, which names the thread and the run. message_chunk events carry the reply as it is written, and tool calls and their results come as events of their own. The stream ends on interrupt when the agent waits for an answer, on error or retry when the turn fails (each says whether to retry the run or send again, in recovery), and on run_end with the run’s outcome. Comment lines keep an idle connection open every 15 seconds.

Closing the connection does not stop the turn; it keeps running on the server.

  • GET /api/v1/threads/{thread_id}/messages/stream reconnects to the thread’s latest turn, or to one run with ?run_id=. Pass the last event id you received as the Last-Event-ID header (or ?last_event_id=) and the stream resumes after it, without repeating what you already have.
  • GET /api/v1/threads/{thread_id}/messages/replay reads back a thread’s turns, finished ones included, as the same kind of events.
  • POST /api/v1/threads/{thread_id}/cancel stops the running turn.

A send can carry a request_key, a UUID you generate for that one message. If the connection drops before you know whether the send arrived, send the same request again with the same key: the server recognizes it and connects you to the run the first copy started, rather than starting a second turn. A send without a key is never deduplicated.