The backend exposes a JSON REST API under /api. When the backend is running, interactive documentation is available at /docs.
{
"id": 1,
"title": "Write release notes",
"description": "Cover the new archive endpoint",
"completed": false,
"archived_at": null,
"created_at": "2026-03-01T09:30:00Z",
"updated_at": "2026-03-01T09:30:00Z"
}GET /api/todosReturns todos, newest first. Archived todos are hidden unless you ask for them.
| Query parameter | Type | Description |
|---|---|---|
completed |
boolean | Return only completed or only open todos. |
include_archived |
boolean | Include archived todos. Defaults to false. |
search |
string | Only return todos whose title or description contains the text, ignoring case. 1 to 100 characters. |
curl "http://localhost:8000/api/todos?completed=false"
curl "http://localhost:8000/api/todos?search=milk"POST /api/todosThe body requires a title (1 to 255 characters) and accepts an optional description. Responds with 201 Created and the new todo.
curl -X POST http://localhost:8000/api/todos \
-H "Content-Type: application/json" \
-d '{"title": "Write release notes", "description": "Cover the new archive endpoint"}'GET /api/todos/{id}Responds with 404 Not Found if the todo does not exist.
PATCH /api/todos/{id}Send only the fields you want to change: title, description, or completed.
curl -X PATCH http://localhost:8000/api/todos/1 \
-H "Content-Type: application/json" \
-d '{"completed": true}'POST /api/todos/{id}/archiveSets archived_at and removes the todo from the default list. Archiving an already archived todo leaves the original timestamp in place. Archived todos are deleted permanently after the retention period, see configuration.
DELETE /api/todos/{id}Responds with 204 No Content.
GET /api/healthReturns {"status": "healthy"}. Used by the Docker Compose health check.