HTTP API
export WARDRIK_URL=http://127.0.0.1:4747curl $WARDRIK_URL/v1/agents -H "Authorization: Bearer $WARDRIK_TOKEN"- The daemon listens on
127.0.0.1:4747. Sethttpinconfig.yamlto change it. - Every request needs
Authorization: Bearer <token>. Create one withwardrik token create. Webhooks and chat apps send none. - Bodies are JSON, up to 8 MB. Webhook and chat app routes accept bodies in any format.
- Every response has a
request-idheader, echoing yours if you sent one. GET /v1/openapi.jsonreturns the OpenAPI 3.1 document for the library's routes. The daemon's own routes (/v1/owners/...,/v1/connections,/v1/tokens) are inwardrik_daemon'spriv/openapi.json.- See Use the HTTP API for a walk-through.
Errors
Section titled “Errors”{"error": {"type": "not_found", "message": "No agent runs under agt_01JF8X5RQ2."}}type |
Status | When |
|---|---|---|
invalid_request |
400 |
malformed or invalid input |
unauthorized |
401 |
missing, unknown, revoked or expired token |
forbidden |
403 |
the token isn't allowed to do this |
not_found |
404 |
doesn't exist, or the token can't access it |
conflict |
409 |
conflicts with current state: no such pending call, agent busy, or defined by a file |
internal |
500 |
a server bug |
not_supported |
501 |
not supported yet |
unavailable |
503 |
temporarily unavailable, such as the store; retry later |
IDs in paths
Section titled “IDs in paths”{agent}is a daemon-generated agent ID:agt_01JF8X5RQ2. URL-encode it as one segment.{owner}is one URL-encoded segment:acme(an org),acme%2F%40jon(a user), ordeployment.?agents=takes agent IDs, one peragents=. If omitted, it means every agent the token can access.
Conversations
Section titled “Conversations”An agent has many conversations. To target one, append /conversations/{conversation} to the agent path:
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/conversations/C1/messages \ -H "Authorization: Bearer $WARDRIK_TOKEN" --json '{"content": "Hi"}'These routes support the conversation path: read, clear (DELETE .../conversations/{conversation}),
messages, decisions, approve, deny, authorization, cancel, stop, events, timeline, runs, calls, stop a
call, and move.
- Clearing a conversation deletes its history. The conversation ID still accepts messages.
- In
openapi.json, a conversation route has nooperationId. Itsx-wardrik-operationnames the operation it serves, such asagent.ask.
Agents
Section titled “Agents”List agents
Section titled “List agents”GET /v1/agents
Lists the agents the token can access.
| Parameter | Type | Description |
|---|---|---|
agents |
string, repeated | agent IDs to list |
curl $WARDRIK_URL/v1/agents -H "Authorization: Bearer $WARDRIK_TOKEN"{"agents": [{"id": "agt_01JF8X5RQ2", "status": "parked", "pending": 0, "node": "wardrik@box1"}]}Each agent has id, conversation, status, pending, node, next_run and spent_today, as
Read an agent describes them.
Read an agent
Section titled “Read an agent”GET /v1/agents/{agent}
Returns the agent's current status and activity.
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2 -H "Authorization: Bearer $WARDRIK_TOKEN"{ "agent": {"id": "agt_01JF8X5RQ2"}, "status": "parked", "pending": 0, "activity": { "doing": [{"type": "wardrik.run.interrupted", "interrupts": [{"id": "toolu_01", "reason": "tool_approval", "message": "Open an issue?", "tool_call_id": "toolu_01"}]}], "since": "2026-10-22T09:00:00.000000Z", "pending": 0 }, "interrupts": [{"id": "toolu_01", "reason": "tool_approval", "message": "Open an issue?", "tool_call_id": "toolu_01"}], "cursor": "W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDFdXQ"}| Field | Type | Description |
|---|---|---|
status |
string | idle, running, parked (pending approval) or asleep |
node |
string or null | the node it runs on; null while asleep |
pending |
integer | messages queued behind the current one |
activity |
object | what it's doing, as activity |
interrupts |
array | calls pending approval |
cursor |
string | where its event log stands; pass it as after |
next_run |
string or null | when its next clock trigger runs |
spent_today |
object | what it spent today |
Define an agent
Section titled “Define an agent”PUT /v1/agents/{agent}
Starts the agent with the definition, or updates a running agent from its next turn.
The body is an agent definition. The daemon only accepts IDs it generated, so
create the agent with POST /v1/owners/{owner}/agents first.
curl -X PUT $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2 -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"instructions": "You watch the incident queue.", "model": "anthropic:claude-sonnet-5", "tools": ["web_search"]}'Returns the agent, as Read an agent does. An unsupported key returns 501.
Read a definition
Section titled “Read a definition”GET /v1/agents/{agent}/definition
Returns the current definition, and lists its tools that aren't available yet.
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/definition -H "Authorization: Bearer $WARDRIK_TOKEN"{"definition": {"instructions": "Answer customers' questions about their orders.", "tools": ["crm/*"]}, "missing": ["crm/*"]}| Field | Type | Description |
|---|---|---|
definition |
object | the definition, as sent |
missing |
array | tools named that aren't there yet, like an MCP server not added |
next_runs |
object | when each trigger runs next, by name; null for a webhook |
Start an agent
Section titled “Start an agent”POST /v1/agents/{agent}/spawn
Starts the agent.
curl -X POST $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/spawn -H "Authorization: Bearer $WARDRIK_TOKEN"{"agent": {"id": "agt_01JF8X5RQ2", "status": "idle", "pending": 0}}Stop an agent
Section titled “Stop an agent”POST /v1/agents/{agent}/stop
Stops the agent's process. The conversation is kept. The next message starts it again.
curl -X POST $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/stop -H "Authorization: Bearer $WARDRIK_TOKEN"{"agent": {"id": "agt_01JF8X5RQ2", "status": "asleep", "pending": 0}}Clear an agent's history
Section titled “Clear an agent's history”DELETE /v1/agents/{agent}/conversation
Clears the agent's history. The agent, its definition and its other conversations are kept. Returns
409 while a turn is running or pending approval.
curl -X DELETE $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/conversation -H "Authorization: Bearer $WARDRIK_TOKEN"Returns the agent, as Read an agent does.
Forget an agent
Section titled “Forget an agent”DELETE /v1/agents/{agent}
Stops the agent and deletes its conversation, definition and triggers. Returns 204.
curl -X DELETE $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2 -H "Authorization: Bearer $WARDRIK_TOKEN"Forget many agents
Section titled “Forget many agents”DELETE /v1/agents
Removes each agent in ?agents=, or every agent the token can access.
| Parameter | Type | Description |
|---|---|---|
agents |
string, repeated | agent IDs to forget |
curl -X DELETE "$WARDRIK_URL/v1/agents?agents=agt_01JF8X5RQ2" -H "Authorization: Bearer $WARDRIK_TOKEN"{"forgotten": ["agt_01JF8X5RQ2"], "kept": [], "failed": []}kept and failed entries are {"id": ..., "why": ...}. An agent an agent file declares is kept.
Move an agent
Section titled “Move an agent”POST /v1/agents/{agent}/move
Restarts the agent on another node. A running turn ends. Send the message again after the move.
| Field | Type | Description |
|---|---|---|
node |
string, required | the node's name |
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/move -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"node": "wardrik@box2"}'{"agent": {"id": "agt_01JF8X5RQ2", "status": "idle", "pending": 0, "node": "wardrik@box2"}}Messages
Section titled “Messages”Send a message
Section titled “Send a message”POST /v1/agents/{agent}/messages
Queues a message for the agent. Returns 202.
| Field | Type | Description |
|---|---|---|
content |
string | the text |
parts |
array | the text as parts, in place of content |
id |
string | your ID for it; a message sent again with the same id is taken once |
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/messages -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"id": "msg_01", "content": "What is on fire?"}'{"message": {"id": "msg_01", "cursor": "W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDFdXQ"}}Read the reply from the events after cursor.
Cancel a turn
Section titled “Cancel a turn”POST /v1/agents/{agent}/cancel
Ends the current turn and drops queued messages. The agent keeps running. Returns 202.
curl -X POST $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/cancel -H "Authorization: Bearer $WARDRIK_TOKEN"Cancel many agents
Section titled “Cancel many agents”POST /v1/agents/cancel
Ends the current turn of each agent in ?agents=, or every agent the token can access. Returns 202.
curl -X POST "$WARDRIK_URL/v1/agents/cancel?agents=agt_01JF8X5RQ2" -H "Authorization: Bearer $WARDRIK_TOKEN"{"cancelled": ["agt_01JF8X5RQ2"]}List running tool calls
Section titled “List running tool calls”GET /v1/agents/{agent}/calls
Lists the agent's running tool calls. Returns 404 while its process is stopped.
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/calls -H "Authorization: Bearer $WARDRIK_TOKEN"{"calls": [{"id": "toolu_01", "name": "github__search_issues", "elapsed_ms": 1250}]}Stop a tool call
Section titled “Stop a tool call”DELETE /v1/agents/{agent}/calls/{call}
Stops one tool call. The model receives an error and the turn continues. Returns 204.
curl -X DELETE $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/calls/toolu_01 -H "Authorization: Bearer $WARDRIK_TOKEN"Approvals
Section titled “Approvals”List waiting calls
Section titled “List waiting calls”GET /v1/interrupts
Lists calls pending approval.
| Parameter | Type | Description |
|---|---|---|
agents |
string, repeated | agent IDs to cover |
curl $WARDRIK_URL/v1/interrupts -H "Authorization: Bearer $WARDRIK_TOKEN"{"interrupts": [{"agent": {"id": "agt_01JF8X5RQ2"}, "interrupt": {"id": "toolu_01", "reason": "tool_approval", "message": "Open an issue?", "tool_call_id": "toolu_01"}}]}An entry has conversation when the call is in a conversation.
Approve a call
Section titled “Approve a call”POST /v1/agents/{agent}/interrupts/{interrupt}/approve
Approves one call. It runs with the model's arguments.
| Field | Type | Description |
|---|---|---|
note |
string | text the model receives with the call's result |
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/interrupts/toolu_01/approve \ -H "Authorization: Bearer $WARDRIK_TOKEN" --json '{"note": "Only staging."}'{"decisions": [{"id": "toolu_01", "decision": "approved"}]}Deny a call
Section titled “Deny a call”POST /v1/agents/{agent}/interrupts/{interrupt}/deny
Denies one call.
| Field | Type | Description |
|---|---|---|
reason |
string | text the model receives instead of the call's result |
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/interrupts/toolu_01/deny \ -H "Authorization: Bearer $WARDRIK_TOKEN" --json '{"reason": "Not this quarter."}'{"decisions": [{"id": "toolu_01", "decision": "rejected"}]}Decide many calls
Section titled “Decide many calls”POST /v1/agents/{agent}/decisions
Approves or denies several pending calls at once.
| Field | Type | Description |
|---|---|---|
decisions[].id |
string, required | the waiting call's ID |
decisions[].decision |
string, required | approve or reject |
decisions[].note |
string | for an approval |
decisions[].reason |
string | for a rejection |
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/decisions -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"decisions": [{"id": "toolu_01", "decision": "reject", "reason": "Not this quarter."}, {"id": "toolu_02", "decision": "approve"}]}'{"decisions": [{"id": "toolu_01", "decision": "rejected"}, {"id": "toolu_02", "decision": "approved"}]}Read a sign-in link
Section titled “Read a sign-in link”GET /v1/agents/{agent}/interrupts/{interrupt}/authorization
Returns the sign-in URL for a call pending with reason authorization.
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/interrupts/toolu_01/authorization \ -H "Authorization: Bearer $WARDRIK_TOKEN"{"url": "https://github.com/login/device", "code": "WDJB-MJHT"}code is there only for a device sign-in.
Events
Section titled “Events”Read events
Section titled “Read events”GET /v1/events
Returns agents' events, as a JSON page or a server-sent event stream.
| Parameter | Type | Description |
|---|---|---|
agents |
string, repeated | agent IDs to read |
types |
string, repeated | event types, like wardrik.run.completed; all unless set |
after |
string | the cursor to read after: a page's next, a streamed event's id, or a snapshot's cursor |
limit |
integer | events per page; 100 unless set |
curl "$WARDRIK_URL/v1/events?agents=agt_01JF8X5RQ2&types=wardrik.run.completed" \ -H "Authorization: Bearer $WARDRIK_TOKEN"{"events": [], "next": "W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDFdXQ"}Stream with Accept: text/event-stream:
curl -N "$WARDRIK_URL/v1/events" -H "Accept: text/event-stream" -H "Authorization: Bearer $WARDRIK_TOKEN"id: W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDJdXQdata: {"specversion":"1.0","type":"wardrik.run.completed","agent":"agt_01JF8X5RQ2",...}- Each event's
idis a cursor. To resume, reconnect withLast-Event-IDor?after=. - Without a cursor, a page starts at the oldest event, and a stream starts at the next new event.
- Deltas have no
id. - An idle stream sends a comment every 15 seconds.
- If the log was trimmed past your cursor, you receive
wardrik.events.dropped, regardless oftypes.
GET /v1/agents/{agent}/events reads one agent's log the same way.
Read the head cursor
Section titled “Read the head cursor”GET /v1/events/head
Returns the current end-of-log cursor, to read only new events.
curl $WARDRIK_URL/v1/events/head -H "Authorization: Bearer $WARDRIK_TOKEN"{"cursor": "W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDFdXQ"}Read a timeline
Section titled “Read a timeline”GET /v1/agents/{agent}/timeline
Returns the conversation in readable form, oldest first.
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/timeline -H "Authorization: Bearer $WARDRIK_TOKEN"{ "items": [ {"id": "msg_01", "kind": "user", "text": "What is on fire?", "sender": "acme/@ana"}, {"id": "run_01", "kind": "run", "status": "completed", "steps": [{"id": "s1", "type": "text", "text": "Nothing right now.", "live": false}]} ], "cursor": "W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDFdXQ"}A run's steps are thinking, text or tool (with name, arguments, status, result).
Read runs
Section titled “Read runs”GET /v1/agents/{agent}/runs
Returns each turn, newest first, with its cost, and totals.
curl $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/runs -H "Authorization: Bearer $WARDRIK_TOKEN"{ "runs": [{"id": "run_01", "status": "completed", "started_at": "2026-10-22T09:00:00Z", "finished_at": "2026-10-22T09:00:04Z", "duration_ms": 4120, "model": "anthropic:claude-sonnet-5", "tool_calls": 2, "tool_errors": 0, "input_tokens": 1830, "output_tokens": 212, "cost_micro_usd": 8670}], "totals": {"runs": 1, "failed": 0, "tool_calls": 2, "input_tokens": 1830, "output_tokens": 212, "cost_micro_usd": 8670, "last_at": "2026-10-22T09:00:04Z"}, "cursor": "W1siYWd0XzAxSkY4WDVSUTIiLG51bGwsNDFdXQ"}Triggers
Section titled “Triggers”Set a trigger
Section titled “Set a trigger”PUT /v1/agents/{agent}/triggers/{trigger}
Sets or changes one trigger. Returns 404 if the agent has no definition.
The body has the keys of a trigger: every, timezone, prompt,
prompt_file, overlap, missed, jitter, feed, webhook.
curl -X PUT $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/triggers/sweep -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"every": "*/30 * * * *", "prompt": "Check the queue.", "overlap": "skip"}'{"every": "*/30 * * * *", "prompt": "Check the queue.", "overlap": "skip"}If every and timezone are unchanged, the trigger keeps its next run time.
Remove a trigger
Section titled “Remove a trigger”DELETE /v1/agents/{agent}/triggers/{trigger}
Deletes the trigger. Returns its last state.
curl -X DELETE $WARDRIK_URL/v1/agents/agt_01JF8X5RQ2/triggers/sweep -H "Authorization: Bearer $WARDRIK_TOKEN"{"every": "*/30 * * * *", "prompt": "Check the queue.", "overlap": "skip"}Deliver a webhook
Section titled “Deliver a webhook”POST /v1/hooks/{agent}/{trigger}
Sends a webhook request to the agent's webhook trigger. Returns 202.
- No token. The request authenticates with the trigger's secret, as
Authorization: Beareror a Standard Webhooks signature. - The body can be any content type. Wardrik passes the body and headers to the agent as sent.
- A repeated request sends one message.
404if the trigger doesn't exist or the secret doesn't match.503means retry later.
curl $WARDRIK_URL/v1/hooks/agt_01JF8X5RQ2/issues \ -H "Authorization: Bearer s3cret" --json '{"action": "opened"}'POST /v1/hooks/{agent}/{trigger}/{secret} takes the secret as the last path segment, for services
that only accept a URL. Treat that URL as a secret.
Channels
Section titled “Channels”Deliver a chat app's request
Section titled “Deliver a chat app's request”POST /v1/channels/{channel}/{path}
Routes a chat app's request, such as a Slack event, to the named channel in config.yaml.
- No token. The channel verifies the request's signature.
- The body can be any content type.
- The response is the channel's status, headers and body, in the chat app's format.
404if no channel with that name accepts requests.
curl $WARDRIK_URL/v1/channels/slack/events \ -H "X-Slack-Signature: v0=a2114d57..." -H "X-Slack-Request-Timestamp: 1531420618" \ --json '{"type": "url_verification", "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}'3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8PSee Slack.
Deployment
Section titled “Deployment”List nodes
Section titled “List nodes”GET /v1/deployment/nodes
Lists the nodes, with the running and stopped agent counts on each.
curl $WARDRIK_URL/v1/deployment/nodes -H "Authorization: Bearer $WARDRIK_TOKEN"{"nodes": [{"name": "wardrik@box1", "agents": 12}, {"name": "wardrik@box2", "agents": 9}], "asleep": 40}Reload definitions
Section titled “Reload definitions”POST /v1/deployment/reload
Rereads every agent's definition, or those in ?agents=. Each applies from the agent's next turn.
curl -X POST $WARDRIK_URL/v1/deployment/reload -H "Authorization: Bearer $WARDRIK_TOKEN"{"reloaded": ["wardrik@box1"], "problems": ["agents/broken.md: There's no tool nope here."]}Read the audit log
Section titled “Read the audit log”GET /v1/deployment/audit
Returns a page of the audit log, oldest first.
| Parameter | Type | Description |
|---|---|---|
starting_after |
integer | the sequence to read after, a page's next |
limit |
integer | changes per page; 100 unless set |
curl "$WARDRIK_URL/v1/deployment/audit?starting_after=11" -H "Authorization: Bearer $WARDRIK_TOKEN"{"events": [{"specversion": "1.0", "type": "wardrik.agent.defined", "...": "..."}], "next": 12}Each entry is a CloudEvent, like an agent's events.
Daemon: agents
Section titled “Daemon: agents”Make an agent
Section titled “Make an agent”POST /v1/owners/{owner}/agents
Generates an agent ID, stores the record, and defines the agent. Returns 201.
| Field | Type | Description |
|---|---|---|
name |
string, required | unique in the org: letters, digits, _, ., - |
| any definition key | the agent's definition |
curl $WARDRIK_URL/v1/owners/acme%2F%40jon/agents -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"name": "notes", "model": "anthropic:claude-haiku-4-5", "instructions": "You keep Jon'\''s notes."}'{"id": "agt_01JF8X5RQ2M3V9ZK0B7Y4T6WHN", "name": "notes", "org": "acme", "owner": "acme/@jon"}workspace.shared names agents of the org by name. A name in use is a 409.
Find agents
Section titled “Find agents”GET /v1/owners/{owner}/agents
Lists the agents in the owner's org that the token can read.
| Parameter | Type | Description |
|---|---|---|
name |
string | the agent's name; every agent unless set |
curl "$WARDRIK_URL/v1/owners/acme/agents?name=notes" -H "Authorization: Bearer $WARDRIK_TOKEN"{"agents": [{"id": "agt_01JF8X5RQ2M3V9ZK0B7Y4T6WHN", "name": "notes", "org": "acme", "owner": "acme/@jon"}]}Daemon: secrets
Section titled “Daemon: secrets”List secrets
Section titled “List secrets”GET /v1/owners/{owner}/secrets
Lists the owner's secret names and purposes, never values.
curl $WARDRIK_URL/v1/owners/acme/secrets -H "Authorization: Bearer $WARDRIK_TOKEN"{"secrets": [{"name": "ANTHROPIC_API_KEY", "purpose": "api_key"}, {"name": "linear", "purpose": "grant"}]}purpose is api_key, client_secret, header, signing_secret, grant (a connected account),
token (a chat app install) or secret.
Seal a secret
Section titled “Seal a secret”PUT /v1/owners/{owner}/secrets/{name}
Stores an encrypted value under the name, replacing any existing one. Returns 204.
| Field | Type | Description |
|---|---|---|
value |
string, required | the secret |
purpose |
string, required | api_key, client_secret, header or signing_secret; it's only read for that |
curl -X PUT $WARDRIK_URL/v1/owners/acme/secrets/ANTHROPIC_API_KEY -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"value": "sk-ant-0123456789abcdef", "purpose": "api_key"}'${NAME} in config.yaml resolves the deployment owner's secrets.
Remove a secret
Section titled “Remove a secret”DELETE /v1/owners/{owner}/secrets/{name}
Removes the secret. Returns 204, even if it didn't exist.
curl -X DELETE $WARDRIK_URL/v1/owners/acme/secrets/ANTHROPIC_API_KEY -H "Authorization: Bearer $WARDRIK_TOKEN"Daemon: ceilings
Section titled “Daemon: ceilings”List ceilings
Section titled “List ceilings”GET /v1/owners/{owner}/ceilings
Lists the org's spending ceilings, with its agents' spend this period.
curl $WARDRIK_URL/v1/owners/acme/ceilings -H "Authorization: Bearer $WARDRIK_TOKEN"{"ceilings": [{"ceiling": "plan", "per": "month", "on_exhausted": "ask", "limit": {"usd": 20.0}, "spent": {"usd": 12.4, "tokens": 81200}, "granted": {}, "starts_over": "2026-11-01"}]}Daemon: MCP servers
Section titled “Daemon: MCP servers”List servers
Section titled “List servers”GET /v1/owners/{owner}/servers
Lists the MCP servers available to the owner's agents: the owner's, then the org's, then the deployment's.
curl $WARDRIK_URL/v1/owners/acme/servers -H "Authorization: Bearer $WARDRIK_TOKEN"{"servers": [{"owner": "acme", "name": "crm", "source": "runtime", "url": "https://mcp.crm.example/mcp", "auth": "secret"}, {"owner": "deployment", "name": "github", "source": "config", "url": "https://api.githubcopilot.com/mcp/", "auth": "oauth"}]}Add a server
Section titled “Add a server”POST /v1/owners/{owner}/servers
Adds an MCP server for the owner's agents. Its tools are available from their next turn. Returns 201.
| Field | Type | Description |
|---|---|---|
name |
string, required | letters, digits, -, _, up to 32, never __; agents name its tools name/* |
url |
string, required | an https Streamable HTTP URL |
auth |
object, required | {"none": {}}, {"secret": {"name": ..., "header": ..., "scheme": ...}}, or {"oauth": {...}} |
only |
array | the server's tool names to take |
except |
array | the server's tool names to leave |
oauth takes scopes, and provider (an OAuth app's name) or issuer, client_id and client_secret.
If empty, the daemon discovers the server's OAuth metadata.
curl $WARDRIK_URL/v1/owners/acme/servers -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"name": "crm", "url": "https://mcp.crm.example/mcp", "auth": {"oauth": {}}}'{"server": "crm", "connected": false, "authorization": {"url": "https://auth.crm.example/authorize?client_id=…&state=…"}}Remove a server
Section titled “Remove a server”DELETE /v1/owners/{owner}/servers/{name}
Removes one of the owner's servers, and deletes its sign-ins.
curl -X DELETE $WARDRIK_URL/v1/owners/acme/servers/crm -H "Authorization: Bearer $WARDRIK_TOKEN"{"owner": "acme", "name": "crm", "source": "runtime", "url": "https://mcp.crm.example/mcp", "auth": "secret"}Daemon: notify targets
Section titled “Daemon: notify targets”List notify targets
Section titled “List notify targets”GET /v1/owners/{owner}/notify_targets
Lists the notice targets available to the owner's agents: the owner's, then the org's, then the deployment's.
curl $WARDRIK_URL/v1/owners/acme/notify_targets -H "Authorization: Bearer $WARDRIK_TOKEN"{"targets": [{"owner": "acme", "name": "ops", "source": "runtime", "kind": "webhook", "url": "https://hooks.acme.example/wardrik", "secret": {"name": "OPS_HOOK_SECRET"}}]}Add a notify target
Section titled “Add a notify target”POST /v1/owners/{owner}/notify_targets
Adds a notice webhook. Returns 201.
| Field | Type | Description |
|---|---|---|
name |
string, required | what definitions name in notify; letters, digits, -, _, up to 32 |
url |
string, required | an https URL; redirects aren't followed |
secret.name |
string | a vault secret that signs each notice |
curl $WARDRIK_URL/v1/owners/acme/notify_targets -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"name": "ops", "url": "https://hooks.acme.example/wardrik", "secret": {"name": "OPS_HOOK_SECRET"}}'{"owner": "acme", "name": "ops", "source": "runtime", "kind": "webhook", "url": "https://hooks.acme.example/wardrik", "secret": {"name": "OPS_HOOK_SECRET"}}Remove a notify target
Section titled “Remove a notify target”DELETE /v1/owners/{owner}/notify_targets/{name}
Removes one of the owner's targets. Returns its last state.
curl -X DELETE $WARDRIK_URL/v1/owners/acme/notify_targets/ops -H "Authorization: Bearer $WARDRIK_TOKEN"Daemon: OAuth apps
Section titled “Daemon: OAuth apps”List OAuth apps
Section titled “List OAuth apps”GET /v1/owners/{owner}/providers
Lists the owner's OAuth apps, never client secrets.
curl $WARDRIK_URL/v1/owners/acme/providers -H "Authorization: Bearer $WARDRIK_TOKEN"{"providers": [{"owner": "deployment", "name": "google", "source": "runtime", "issuer": "https://accounts.google.com", "client_id": "868288504182-example.apps.googleusercontent.com", "client_secret": {"name": "GOOGLE_CLIENT_SECRET"}, "scopes": ["https://www.googleapis.com/auth/adwords"], "client_auth": "post", "flow": "browser"}]}Add an OAuth app
Section titled “Add an OAuth app”POST /v1/owners/{owner}/providers
Adds an OAuth app for the owner's users. Returns 201.
| Field | Type | Description |
|---|---|---|
name |
string, required | the account it grants; letters, digits, -, _, up to 32 |
issuer |
string | the issuer URL; its metadata names the endpoints |
resource |
string | the API its tokens are for; finds the issuer if none is given |
authorization_endpoint, token_endpoint |
string | for a service without metadata |
client_id |
string | the app's client ID |
client_secret.name |
string | a vault secret stored as client_secret |
client_auth |
string | post (default) or basic |
scopes |
array | scopes to ask for |
flow |
string | browser (default) or device |
authorization_params |
object | extra browser sign-in params, like access_type |
It requires issuer, resource, or both endpoints.
curl $WARDRIK_URL/v1/owners/acme/providers -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"name": "x", "authorization_endpoint": "https://x.com/i/oauth2/authorize", "token_endpoint": "https://api.x.com/2/oauth2/token", "client_id": "cnh3-example", "client_secret": {"name": "X_CLIENT_SECRET"}, "client_auth": "basic", "scopes": ["tweet.read", "tweet.write", "offline.access"]}'Returns the stored app, in the format of List OAuth apps.
Remove an OAuth app
Section titled “Remove an OAuth app”DELETE /v1/owners/{owner}/providers/{name}
Removes one of the owner's apps. Returns its last state.
curl -X DELETE $WARDRIK_URL/v1/owners/acme/providers/x -H "Authorization: Bearer $WARDRIK_TOKEN"Daemon: connections
Section titled “Daemon: connections”The token user's connected accounts. Any token can manage its own.
List connections
Section titled “List connections”GET /v1/connections
Lists the available providers, and whether each is connected.
curl $WARDRIK_URL/v1/connections -H "Authorization: Bearer $WARDRIK_TOKEN"{"connections": [{"provider": "github", "connected": true, "signing_in": false}, {"provider": "linear", "connected": false, "signing_in": true}]}| Field | Type | Description |
|---|---|---|
provider |
string | an OAuth app's name, or an MCP server's with its own sign-in |
connected |
boolean | whether it's connected |
signing_in |
boolean | whether a sign-in you started is still under way |
Connect an account
Section titled “Connect an account”POST /v1/connections/{provider}
Starts a sign-in, or returns connected: true if already connected.
curl -X POST $WARDRIK_URL/v1/connections/github -H "Authorization: Bearer $WARDRIK_TOKEN"{"provider": "github", "connected": false, "authorization": {"url": "https://github.com/login/device", "code": "WDJB-MJHT"}}Open authorization.url. For a device sign-in, enter code there.
Finish a browser sign-in
Section titled “Finish a browser sign-in”POST /v1/connections/{provider}/pair
Completes a browser sign-in with the code from its page. Five wrong codes cancel the sign-in.
| Field | Type | Description |
|---|---|---|
code |
string, required | the code, as BCDF-GHJK |
curl $WARDRIK_URL/v1/connections/linear/pair -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"code": "BCDF-GHJK"}'{"provider": "linear", "connected": true, "signing_in": false}Disconnect an account
Section titled “Disconnect an account”DELETE /v1/connections/{provider}
Forgets your account. The next call that needs it asks you to sign in again. Returns 204, or
404 if there is no such connection.
curl -X DELETE $WARDRIK_URL/v1/connections/github -H "Authorization: Bearer $WARDRIK_TOKEN"Daemon: tokens
Section titled “Daemon: tokens”List tokens
Section titled “List tokens”GET /v1/tokens
Lists every token, never secrets.
curl $WARDRIK_URL/v1/tokens -H "Authorization: Bearer $WARDRIK_TOKEN"{"tokens": [{"id": "mzxw6ytboi", "name": "ana's laptop", "subject": "user:acme/@ana", "groups": ["payments-eng"], "expires": "2026-12-01T00:00:00Z"}]}Create a token
Section titled “Create a token”POST /v1/tokens
Creates a token that authenticates as subject. Returns 201 with the secret, shown once.
| Field | Type | Description |
|---|---|---|
name |
string, required | what it's for |
subject |
string, required | a person, as user:acme/@ana, or agent:ID for an agent's own |
groups |
array | the user's groups, which bindings can name |
expires_in |
integer | seconds, from 60 to a year; 30 days unless set |
curl $WARDRIK_URL/v1/tokens -H "Authorization: Bearer $WARDRIK_TOKEN" \ --json '{"name": "ana laptop", "subject": "user:acme/@ana", "groups": ["payments-eng"], "expires_in": 2592000}'{"id": "mzxw6ytboi", "name": "ana laptop", "subject": "user:acme/@ana", "groups": ["payments-eng"], "expires": "2026-12-01T00:00:00Z", "secret": "wdk_mzxw6ytboi_0123456789abcdef"}Only the admin user can create a user:admin token.
Revoke a token
Section titled “Revoke a token”DELETE /v1/tokens/{id}
Revokes the token immediately. Returns 204.
curl -X DELETE $WARDRIK_URL/v1/tokens/mzxw6ytboi -H "Authorization: Bearer $WARDRIK_TOKEN"Tool workers
Section titled “Tool workers”GET /v1/workers is a WebSocket for an MCP server that dials in. See Tools in your app.
- Messages are JSON-RPC 2.0, one per text frame, as MCP
2025-06-18. - Wardrik is the client. It sends
initialize,tools/list,tools/callandnotifications/cancelled. - A call's
_metahas the callingagentand anidempotencyKey. Return_meta.costUsdto report cost. - Agents with
workers/*intoolssee the worker's tools asworkers__NAME. - A non-WebSocket request with a valid token returns
426. The socket closes with1008when the token is revoked or expires.