REST API Reference

The REST API is served under the prefix /api/v1 (configurable via API_PREFIX). All REST routes are gated by the API-key dependency when authentication is enabled — see authentication.html.

Interactive Swagger UI is available at /docs and the OpenAPI schema at /openapi.json.

Conventions

Health

GET /health

Public. Returns effective runtime posture so operators can verify config without authenticating.

{
  "status": "ok",
  "api_version": "0.2.0",
  "protocol": "a2a",
  "default_model": "gpt-4o-mini",
  "mcp_tools": 1,
  "auth": { "enabled": false, "configured": false, "header": "X-API-Key" },
  "cors": { "enabled": true, "wildcard_origin": true, "credentials": false }
}

Personas

GET /api/v1/personas

List all loaded personas.

{
  "personas": [
    { "id": "trump", "name": "Donald Trump", "description": "45th President of the United States…" }
  ]
}

GET /api/v1/personas/{persona_id}

Get full persona details (background, language style, knowledge domains, interaction samples).

POST /api/v1/personas

Create a new persona. Returns 201.

Request:

{
  "name": "Albert Einstein",
  "description": "Theoretical physicist…",
  "personal_background": { "birth": "1879-03-14", "profession": "Physicist" },
  "language_style": { "tone": "Thoughtful" },
  "knowledge_domains": { "physics": ["relativity"] },
  "interaction_samples": [
    { "type": "quote", "content": "Imagination is more important than knowledge." }
  ],
  "system_prompt": null
}

PUT /api/v1/personas/{persona_id}

Partial update; any field omitted from the body is preserved. Returns the updated persona.

DELETE /api/v1/personas/{persona_id}

Delete the persona and any persona files inside PERSONAS_DIR. Files outside the directory (e.g. via symlink) are skipped defensively.

POST /api/v1/personas/upload

Upload a .json, .yaml, or .yml file via multipart/form-data. Returns 201 with the created persona.

Agents

An agent binds a persona to an executor that manages chat with the LLM and MCP tools.

GET /api/v1/agents

List all active agents.

{
  "agents": [
    { "id": "<uuid>", "persona_id": "trump", "name": "Donald Trump", "created_at": 1715846400.0 }
  ]
}

GET /api/v1/agents/{agent_id}

Get a single agent. 404 if not found.

POST /api/v1/agents

Create an agent for a persona. Returns 201.

Request:

{ "persona_id": "trump", "model": null }

DELETE /api/v1/agents/{agent_id}

Delete an agent and any sessions bound to it. 404 if not found.

Sessions

A session is a conversation with a single agent; messages are buffered in the executor’s per-context history.

GET /api/v1/sessions

List all active sessions with metadata.

{
  "sessions": [
    {
      "id": "<uuid>",
      "agent_id": "<uuid>",
      "persona_id": "trump",
      "message_count": 4,
      "created_at": 1715846400.0,
      "last_active": 1715846412.7
    }
  ]
}

GET /api/v1/sessions/{session_id}

Get session metadata. 404 if not found.

POST /api/v1/sessions

Create a new session bound to an existing agent. Returns 201.

Request:

{ "agent_id": "<uuid>" }

DELETE /api/v1/sessions/{session_id}

Delete the session and clear its executor history.

GET /api/v1/sessions/{session_id}/messages

Return the full message history for the session.

{
  "session_id": "<uuid>",
  "messages": [
    { "role": "user", "content": "Hi", "timestamp": 1715846400.0 },
    { "role": "assistant", "content": "Hello!", "timestamp": 1715846401.4 }
  ]
}

Older history entries written before timestamp tracking surface timestamp: 0.0.

POST /api/v1/sessions/{session_id}/messages

Send a message and wait for the agent’s response.

Request:

{ "message": "What's your view on trade policy?" }

Response:

{
  "session_id": "<uuid>",
  "success": true,
  "response": "<assistant reply>",
  "error_details": null
}

A2A discovery

The A2A protocol surfaces are documented in a2a-protocol.html. They are public (no API-key gate) by protocol design.

Status codes

Code Meaning
200 Success.
201 Resource created (POST /personas, /agents, /sessions, /personas/upload).
400 Malformed input (bad upload filename or content).
401 Auth enabled and header missing or invalid.
404 Resource not found.
422 Request body fails Pydantic / FastAPI validation (e.g. wrong type, missing required field).
500 Internal failure (file write, agent creation, persona save).
503 Auth enabled but the allow-list is empty (misconfiguration).

Most non-2xx responses use the { "detail": "<message>" } shape and never contain exception text or stack traces. The exception is 422, where FastAPI populates detail with a list of per-field validation error objects:

{
  "detail": [
    {
      "loc": ["body", "agent_id"],
      "msg": "Field required",
      "type": "missing"
    }
  ]
}

Clients should handle 422 separately from the string-detail shape. See FastAPI’s validation error format for the full schema.