How do I have conversations through the API?
http://localhost:3001 Daemion organizes conversations into threads made up of turns. A thread belongs to an agent and optionally a project. Turns are what most APIs call messages — Daemion uses the term “turns” throughout the API and WebSocket events.
How do I send a message?
Send a message to an agent. Returns 201 immediately with the user turn object — the actual agent response streams over WebSocket.
| Parameter | Type | Description |
|---|---|---|
threadId | string | Thread to post into. If omitted, a new thread is created automatically. |
content REQUIRED | string | The message text to send to the agent. |
agentId | string | Which agent handles the message. Defaults to the thread's agent if threadId is provided. |
model | string | Model ID to use for this request. Defaults to claude-sonnet-4-6. |
curl -X POST http://localhost:3001/chat
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{
“content”: “Summarize what we discussed last week”,
“agentId”: “opus”
}’
Response (201 — the inserted user turn):
{ “id”: “trn_07xyz456”, “thread_id”: “thr_01abc123”, “role”: “user”, “content”: “Summarize what we discussed last week”, “created_at”: “2026-03-31T08:00:00Z” }
ws://localhost:3001 before sending the chat request. The gateway streams turn events in real time — text-delta for each chunk, finish when the agent finishes, stopped if aborted. The turn id in the 201 response matches the events.threadId, a new thread is created automatically for you. The thread_id in the response is the one to use for follow-up messages./chat/stop with the threadId. The agent stops processing and the WebSocket emits a stopped event. The partial turn is saved.How do I stop an in-progress response?
Abort an agent response that is currently streaming.
| Parameter | Type | Description |
|---|---|---|
threadId REQUIRED | string | The thread whose active response should be stopped. |
curl -X POST http://localhost:3001/chat/stop
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “threadId”: “thr_01abc123” }‘
How do I list conversations?
List threads, with optional filters. Returns threads in reverse chronological order.
| Parameter | Type | Description |
|---|---|---|
agent_id | string | Filter to threads belonging to a specific agent. |
project_id | string | Filter to threads in a specific project. |
job_id | string | Filter to threads created by a specific job run. |
archived | boolean | Set to true to include archived threads. Defaults to false. |
since | string (ISO 8601) | Return only threads updated after this timestamp. |
curl “http://localhost:3001/threads?agent_id=opus&archived=false”
-H “Authorization: Bearer $DAEMION_TOKEN”
How do I create a thread explicitly?
Create a new thread. Useful when you want to set a title or attach to a project before sending the first message.
| Parameter | Type | Description |
|---|---|---|
agent_id | string | The agent this thread belongs to. |
title | string | Human-readable title for the thread. Auto-generated if omitted. |
project_id | string | Project to attach this thread to. |
curl -X POST http://localhost:3001/threads
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{
“agent_id”: “sonnet”,
“title”: “Q2 planning notes”,
“project_id”: “proj_q2”
}‘
How do I update a thread?
Update a thread's title, archived state, or mode.
| Parameter | Type | Description |
|---|---|---|
title | string | New title for the thread. |
archived | boolean | Set to true to archive, false to unarchive. |
mode | string | Override the execution mode for this thread. |
curl -X PATCH http://localhost:3001/threads/thr_01abc123
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{ “archived”: true }‘
How do I read message history?
Return the turns (messages) in a thread, newest first.
| Parameter | Type | Description |
|---|---|---|
limit | number | Maximum number of turns to return. Defaults to 50. |
before | string | Cursor — return turns older than this turn_id. |
role | string | Filter by role: user or assistant. |
since | string (ISO 8601) | Return only turns created after this timestamp. |
Daemion calls conversation entries turns, not messages. This distinction is consistent across the REST API, WebSocket events, and the database schema.
curl “http://localhost:3001/threads/thr_01abc123/turns?limit=20&role=assistant”
-H “Authorization: Bearer $DAEMION_TOKEN”
How do I write a turn directly?
Insert a turn into a thread without invoking the agent. Useful for seeding context or injecting system notes.
| Parameter | Type | Description |
|---|---|---|
content REQUIRED | string | Turn content. |
role REQUIRED | string | Role for this turn: user, assistant, system, or tool. |
metadata | object | Arbitrary key-value metadata attached to this turn. |
curl -X POST http://localhost:3001/threads/thr_01abc123/turns
-H “Authorization: Bearer $DAEMION_TOKEN”
-H “Content-Type: application/json”
-d ’{
“role”: “user”,
“content”: “Context from last week: the deadline moved to April 15.”,
“metadata”: { “source”: “import” }
}‘
How do I delete a turn?
Permanently delete a turn by ID.
curl -X DELETE http://localhost:3001/turns/trn_07xyz456
-H “Authorization: Bearer $DAEMION_TOKEN”
How do I search across conversations?
Full-text search across turns using SQLite FTS5. Searches content of all turns for the given agent.
| Parameter | Type | Description |
|---|---|---|
q REQUIRED | string | Search query. Supports FTS5 syntax: phrases in quotes, prefix wildcards with *. |
agent_id REQUIRED | string | Scope search to turns belonging to this agent. |
limit | number | Maximum results to return. Defaults to 20. |
thread_id | string | Narrow search to a single thread. |
curl “http://localhost:3001/turns/search?q=deadline+april&agent_id=opus&limit=10”
-H “Authorization: Bearer $DAEMION_TOKEN”
"exact phrase" for phrase matching, term* for prefix search, and term1 AND term2 for boolean AND. Example: q="project deadline" april*.id, thread_id, role, content, created_at, and any metadata. Results are ranked by FTS5 relevance score.What can go wrong
401 {"error": "unauthorized"} — Bearer token is missing, wrong, or from an unpaired device. Re-pair the device to get a fresh token, then update your Authorization header.
400 {"error": "agent not found"} — The agent_id you passed doesn’t match any agent extension in the gateway’s database. Check GET /extensions?type=agent to see what’s registered.
400 {"error": "agent is disabled"} — The agent exists but has been toggled off. Enable it in the Daemion app under Settings > Agents, or PATCH the extension record directly.
No WebSocket events after POST /chat — You must connect to the WebSocket before sending the chat request. If you connect after, you’ll miss the turn.delta stream for that turn. Establish the connection once at startup and keep it open.
What’s next?
- Extensions API — manage agents, jobs, and other extensions
- WebSocket events — real-time turn streaming reference
- Quickstart — get the full setup running end to end