API reference
API reference
Section titled “API reference”Authentication
Section titled “Authentication”All endpoints require a bearer token. Pass a JWT or API key issued by the
identity service in the Authorization header:
Authorization: Bearer <token>The token is validated by calling identity.v1.AuthServiceClient.VerifyToken
on every request. Missing or invalid tokens return 401.
REST endpoints
Section titled “REST endpoints”Agents
Section titled “Agents”POST /v1/agents
Section titled “POST /v1/agents”Create an agent.
Request body
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | yes | non-empty |
slug | string | yes | non-empty, unique/org |
model | string | yes | non-empty |
systemPrompt | string | no | optional system prompt |
// from paper-board/agents/internal/api/api.go:87-92var req struct { Name string `json:"name"` Slug string `json:"slug"` Model string `json:"model"` SystemPrompt string `json:"systemPrompt,omitempty"`}Response — 201 Created with Agent object.
Errors — 400 invalid JSON or missing required fields; 409 slug already
exists within the org.
GET /v1/agents
Section titled “GET /v1/agents”List agents for the authenticated org. Cursor-paginated.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 20 | 1–100; 400 outside range |
after | string | — | Opaque cursor from previous next |
Response — 200 OK
{ "items": [ /* Agent objects */ ], "next": "eyJzb3J0IjoiY3JlYXRlZF9hdCIsInZhbCI6IjIwMjYtMDU..."}next is null when no further pages exist.
GET /v1/agents/{id}
Section titled “GET /v1/agents/{id}”Fetch one agent by UUID.
Path parameters — id: UUID of the agent.
Response — 200 OK with Agent object.
Errors — 400 malformed UUID; 404 agent not found or belongs to a
different org.
Sessions
Section titled “Sessions”POST /v1/sessions
Section titled “POST /v1/sessions”Create a session for an agent.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
agentId | string | yes | UUID of the agent |
Response — 201 Created with Session object.
Errors — 400 malformed UUID; 404 agent not found within the org.
GET /v1/sessions/{id}
Section titled “GET /v1/sessions/{id}”Fetch a session and its full event log.
Response — 200 OK
{ "session": { /* Session object */ }, "events": [ /* SessionEvent objects */ ]}POST /v1/sessions/{id}/prompt
Section titled “POST /v1/sessions/{id}/prompt”Send messages and stream the LLM response as Server-Sent Events (SSE).
Request headers (required for SSE clients):
Accept: text/event-streamContent-Type: application/jsonRequest body
| Field | Type | Required | Description |
|---|---|---|---|
messages | []Message | yes | Non-empty array |
Message shape:
| Field | Type | Notes |
|---|---|---|
role | string | user | assistant | tool |
content | string | Text content |
toolUseId | string | Set when role is tool |
isError | bool | Set when tool result signals an error |
Response — 200 OK, Content-Type: text/event-stream
// from paper-board/agents/internal/api/sse.go:60-63w.Header().Set("Content-Type", "text/event-stream")w.Header().Set("Cache-Control", "no-cache")w.Header().Set("X-Accel-Buffering", "no")SSE event types
Section titled “SSE event types”Each SSE line has the form data: <JSON>\n\n. The JSON object carries a type
field that identifies the event.
// from paper-board/agents/internal/api/sse.go:78-83type sseEvent struct { Type string `json:"type"` Content string `json:"content,omitempty"` TokensIn int `json:"tokensIn,omitempty"` TokensOut int `json:"tokensOut,omitempty"`}type | Payload fields | Description |
|---|---|---|
text | content | One streamed text fragment from the LLM |
tool_use | content (tool name + input JSON) | LLM requested a tool call |
tool_result | content (stdout/exit code) | Result returned from compute; fed back to LLM |
done | tokensIn, tokensOut | Stream complete; cumulative token counts |
error | content (error message) | Terminal error; stream closes after this event |
The stream closes after done or error. Clients must handle both.
Health endpoints
Section titled “Health endpoints”| Path | Auth | Description |
|---|---|---|
GET /livez | no | Returns 200 when the process is alive |
GET /healthz | no | Returns 200 when the process is alive |
GET /readyz | no | Returns 200 when DB + identity gRPC are reachable |
gRPC RPCs
Section titled “gRPC RPCs”The agents service does not expose a public gRPC server in Phases 1–6. It acts as a gRPC client toward identity and compute.
Outbound calls made by agents
| Service | RPC | Purpose |
|---|---|---|
identity.v1.AuthServiceClient | VerifyToken | Authenticate every HTTP request |
compute.v1.ComputeServiceClient | ExecCommand, CreateSandbox, etc. | Tool dispatch (Phase 3+) |
Proto source: paper-board/proto/identity/v1/auth.proto and
paper-board/proto/compute/v1/compute.proto.
Error codes
Section titled “Error codes”The SDK maps Postgres and sentinel errors to HTTP status codes at the handler boundary.
// from paper-board/agents/internal/store/errors.go:24-36func mapErr(err error, op string) error { if err == nil { return nil } if errors.Is(err, pgx.ErrNoRows) { return pberrs.Wrap(pberrs.ErrNotFound, op) } var pgErr *pgconn.PgError if errors.As(err, &pgErr) && strings.HasPrefix(pgErr.Code, "23") { return pberrs.Wrap(pberrs.ErrConflict, op, "constraint", pgErr.ConstraintName) } return pberrs.Wrap(pberrs.ErrInternal, op, "cause", err.Error())}| SDK sentinel | HTTP status | When |
|---|---|---|
ErrInvalidInput | 400 | Malformed JSON, missing field, bad UUID |
ErrUnauthorized | 401 | Missing or invalid bearer token |
ErrNotFound | 404 | Row not found, or row belongs to diff org |
ErrConflict | 409 | Unique constraint violation (e.g., slug) |
ErrUnavailable | 503 | LLM provider unreachable |
ErrInternal | 500 | Unexpected Postgres or internal error |
All error responses use the SDK envelope shape:
{ "error": { "code": "not_found", "message": "get agent" }}