API overview
The portal’s API is the JSON-over-HTTP API that the web app uses. Every path starts with /api.
The endpoint pages under Endpoints in the sidebar are generated from the backend’s OpenAPI
schema.
Authentication
Section titled “Authentication”The API uses the same session cookie as the web app, factory_session. There are no API tokens
yet.
- Open
GET /api/auth/loginin a browser. It redirects to GitHub, then back toGET /api/auth/callback, which sets the cookie. - Send the cookie with every request. In the browser this happens on its own, since the web app and the API share an origin.
Native apps get the same cookie through a PKCE exchange instead: GET /api/auth/login?app_challenge=…
redirects back to the app with a code, which POST /api/auth/app/session exchanges for the cookie.
See Security.
A request without a valid session gets 401 {"detail": "Not signed in"}.
Requests act on the viewer’s current workspace. Change it with POST /api/auth/workspace, and
read it from GET /api/auth/me.
Conventions
Section titled “Conventions”| Topic | Convention |
|---|---|
| Bodies | JSON, snake_case fields |
| IDs | UUID strings, except numeric GitHub IDs such as repo_id and github_repo_id |
| Times | ISO 8601 with a time zone |
| Create | 201 with the created object |
| Delete | 204 with no body |
| Errors | {"detail": "A sentence for a person"}. Validation errors (422) use FastAPI’s list form. |
| Other workspaces | A row in another workspace answers 404, as if it did not exist |
| Streams | GET /api/threads/{id}/events is Server-Sent Events, not JSON: id is the event’s seq, event is agent, and data is the event. Resume with ?after= or Last-Event-ID. |
Status codes
Section titled “Status codes”| Code | Meaning |
|---|---|
400 |
The request is valid but not allowed now, for example removing the default repository |
401 |
Not signed in |
403 |
Signed in, but the role does not allow it |
404 |
Not found in this workspace |
409 |
Conflict: a duplicate name or invite, the sandbox is not running, or the agent is not connected |
422 |
Invalid input |
501 |
The sandbox provider does not support this feature |
502 |
GitHub or the sandbox provider failed |
Response schemas
Section titled “Response schemas”Most routes return plain dictionaries, so the generated reference shows request bodies and
parameters in full, but responses only as object. The TypeScript types in frontend/src/api.ts
describe the responses the web app relies on. Adding Pydantic response models to a route makes its
response appear here.
Interactive docs
Section titled “Interactive docs”The running backend also serves FastAPI’s own Swagger UI at /docs and the schema at
/openapi.json on the API port (8000 by default). Those reflect the code you are running, while this
site shows the schema committed in docs/public/openapi.json.
Keep the schema current
Section titled “Keep the schema current”After any change to a route, its parameters or its models:
cd docspnpm openapiThis runs scripts/export_openapi.py with the backend’s Python environment and rewrites
docs/public/openapi.json. The script adds two things the app does not declare: the local server
URL for the request examples, and the factory_session cookie on every route that answers 401
without it. It finds those routes by calling each one without a cookie, so it needs no database.
Commit the file with the API change.
