Enterprise Serve any agent command defined in your agent configuration over HTTP, with optional real‑time streaming via Server‑Sent Events (SSE). This guide explains what the server does, how to run it, the available endpoints, request/response formats, streaming, sessions, timeouts, and common usage patterns.Documentation Index
Fetch the complete documentation index at: https://docs.qodo.ai/llms.txt
Use this file to discover all available pages before exploring further.
Overview
- Purpose: Turn your agent commands into HTTP endpoints. Each command becomes a POST /webhook/.
- Modes of use:
- One‑shot request: POST and wait for the final JSON response
- Two‑step streaming: POST to start, then connect to an SSE stream to receive incremental updates until completion
- Typical use cases: Integrations with your CI/CD, backend workflows, or any external systems that want to trigger agents programmatically.
Prerequisites
- QODO_API_KEY must be set and valid for your environment.
- A valid agent configuration file (agent.toml/agent.yaml/agent.yml) must be available in the current working directory or parent directories.
Start the server
- Command:
qodo --webhook- Optional port override:
qodo --webhook -p 6666
- Default port: 6666. The server will search for the first available port at or above the requested port.
- Exposed commands:
- By default, every command in your agent config is exposed at
/webhook/{commandName}. - If you start Qodo targeting a specific command or use a single‑command agent file, only that command is exposed.
- By default, every command in your agent config is exposed at
- Shutdown:
- Press ESC or Ctrl+C to exit.
Endpoints
1) POST /webhook/
Trigger an agent command. Choose between a one‑shot (no streaming) or a two‑step streaming workflow.- Query parameters:
sse(boolean): If present and truthy, the server returns{ sessionId }immediately, and you then connect to SSE (see below).stream(boolean): Optional; streaming is effectively enabled wheneversseis provided.sessionId(string): Optional; reuse an existing session (also supported as anX-Session-IDheader). If omitted, the server generates a new sessionId.
- Headers:
X-Session-ID(optional on request): Reuse an existing session.X-Session-ID(always on response): The sessionId used for this request.
- Request body (JSON):
- Fields must match your command’s
argumentsdefinition in the agent config. Invalid payloads return a 400 status code with validation errors.
- Fields must match your command’s
- Responses:
- 200 (non‑SSE): Final JSON result. If your agent emits structured output, that JSON is returned; otherwise
{ "result": "<final text>" }. - 200 (SSE mode):
{ "sessionId": "<id>" }so you can open an SSE stream. - 400: Invalid payload →
{ error: string, details?: any[] } - 500: Internal error (includes a readable message when possible)
- 200 (non‑SSE): Final JSON result. If your agent emits structured output, that JSON is returned; otherwise
2) GET /webhook/?sessionId=…
Server‑Sent Events (SSE) stream for a session started via POST withsse=true.
- Query parameters:
sessionId(required): The sessionId returned by the POST call.
- SSE events:
event: messagedata: { "content": string }– incremental agent messagesevent: errordata: { "error": string }– error messagesevent: loadingdata: { "isLoading": boolean }– task activity flagevent: donedata: {}– sent right before the stream closes (completion)
- Errors:
- 400: missing/invalid
sessionId - 404: unknown
commandNameorsessionId
- 400: missing/invalid
Request validation
Incoming JSON is validated against your command’sarguments schema:
- Supported types:
string,number,boolean,array,object - Required by default unless a field has
required: false - Defaults and enums (if provided) are applied/validated
- On validation error: HTTP 400 with details
Sessions and lifecycle
- Session assignment:
- Provide
X-Session-IDheader or?sessionId=to reuse an existing session. - If omitted, the server obtains a fresh sessionId from the backend and returns it.
- Provide
- Session storage:
- Each session is backed by an internal message manager that tracks AI messages, error state, and loading state.
- Cleanup & TTL:
- Non‑SSE: the session is cleaned up after the response is sent.
- SSE: the session is cleaned up when
loading=false(you’ll receive a finaldoneevent) or if the client disconnects. - Periodic cleanup removes sessions older than 90 minutes. Cleanup runs every 5 minutes.
- Timeout (non‑SSE only):
- The synchronous POST request has a 90-minute timeout and returns a 500 error if exceeded.
Continue an existing session
To keep working within the same session context:- Include
X-Session-ID: <SESSION_ID>on the POST/webhook/{commandName}request. The server will reuse that session and its context/history. - For streaming:
- Start the task with
POST /webhook/{commandName}?sse=trueand the sameX-Session-IDheader (or passsessionId=<SESSION_ID>in the query). - Connect to
GET /webhook/{commandName}?sessionId=<SESSION_ID>to receive events.
- Start the task with
-
You can take the session ID from the
X-Session-IDresponse header of a prior request, or from the{ "sessionId": "..." }returned when usingsse=true. -
If the session was already cleaned up (completion/timeout/TTL), reusing its ID returns 404. Start a new task (optionally with
sse=true) to create a fresh session.
Example
review command that analyzes code changes (diffs/PRs) and returns structured findings.
- Arguments:
pr(string, optional): URL of the pull request to analyze (recommended when using webhook mode).
- Output (structured):
- An object with
summaryandfindings[]. - Each finding includes:
finding_title,severity_level(“breaking-issue” | “concern”),repo_name,file_path,reason,diff_pointer,recommended_fix, andevidence. diff_pointershape (as defined in the command’s schema) includes:start_line,end_line, andhunk_header.
- An object with
A) One‑shot (no streaming)
review), the response will be the structured JSON. Otherwise, it falls back to { "result": "<final text>" }.
B) Two‑step with SSE
C) Reusing a session
Options and flags that influence behavior
--webhook– start the webhook server-p, --port– set the starting port (default: 6666)- Tool selection:
--tool <name>(repeatable) or--tools=name1,name2--no-tool <server.tool>(repeatable) or--no-tools=server.tool1,server.tool2
- Permissions:
--permissions <r|rw|rwx|->to override command permissions
Security considerations
- The server does not enforce HTTP authentication. Treat it as a development/local service or place it behind your API gateway/reverse proxy that handles auth and TLS.
- Ensure QODO_API_KEY is set appropriately and that you don’t expose this server publicly without protections.
Troubleshooting
- 400 Invalid Payload:
- Ensure your request body matches the command’s
argumentsdefinition (forreview, the optionalprstring).
- Ensure your request body matches the command’s
- 404 Not Found:
- Check the
commandNamepath, and ensuresessionIdis valid for SSE.
- Check the
- 500 Internal Error / Timeout:
- Non‑SSE POST requests time out after 90 minutes. Use SSE for long‑running tasks.
- No output / empty result:
- If the agent produced no messages, the non‑SSE response falls back to
{ "result": "No response" }.
- If the agent produced no messages, the non‑SSE response falls back to
Notes
- Requests are executed in a non‑interactive, webhook‑friendly manner. Do not expect to receive user prompts or approvals through this interface.
- For long-running operations and real-time visibility into progress, prefer the two-step SSE pattern.