Daimon

api

Run your agents from your own stack.

Everything the console does to your fleet — spawn, list, pause, resume, read usage — over plain HTTP with one bearer token. The token is scoped to your wallet: it only ever sees your agents.

Building something that talks to an agent? Chat with an agent from your code — one key per agent, one POST.

Get an operator token

  1. Open the console and connect the Sui wallet used to create your fleet.
  2. In settings, under operator api, press issue token. It starts with dmn_op_ and is shown once — we keep only its hash.
  3. Send it as authorization: Bearer …. Regenerating revokes the previous token immediately.

Operator routes

Base URL https://daimon.run. JSON in, JSON out.

  • GET /api/v1/agentsYour agents, newest first. agent_obj_id is the Sui object ID and identifies the account inside it. See the exact response fields below.
  • POST /api/v1/agentsSpawn an agent. All fields optional: template_id (≤ 64 UTF-8 bytes), model (a slug from the supported list; others return 400), system_prompt (≤ 2,000 UTF-8 bytes). Ownership comes from the token, never from the body.
  • POST /api/v1/agents/:id/pauseStop the agent's loop. It keeps its Sui account, key history, and ledger.
  • POST /api/v1/agents/:id/resumeStart it again. Refused for a retired agent — retire is irreversible.
  • GET /api/v1/usageA 14-day usage report across your agents.

Operator responses

GET /api/v1/agents returns an array. Each row has agent_obj_id, persona, status, created_at, tool_notify_owner, tool_http_fetch, and tool_web_search. name, model, template_id, solana_pubkey, and linked_bot_username are omitted when absent. The tool flags default to false and the bot handle is absent on this list route; use the console for current skill settings. The legacy solana_pubkey field does not identify a Sui account: use agent_obj_id.

POST /api/v1/agents returns 201 with agent_obj_id, owner_cap_id, persona, name, owner_token, dashboard_url, model, solana_pubkey, funded, funding, and funding_note. On Sui, solana_pubkey is an empty string. The name, model, and funding note may be null. Keep owner_token private. Check funded and funding before assuming the starting deposit arrived: funding can be pending or unfunded. funding_amount_micro, funding_have_micro, and funding_need_microappear only when a Telegram owner's second or later agent is funded from their Daimon credit at spawn (what moved, and the credit against what an agent needs to start); operator-token spawns never carry them.

Pause and resume return agent_obj_id and status. Usage returns calls_daily (14 UTC days, with day, calls, spend_micro), summary (7 days: calls_7d, spend_7d_micro, avg_per_call_micro, walks), and by_template (7 days: template, spend_micro, share as an integer percentage). Spend is measured in micro-USDC.

Try the operator api

# list your agents
curl https://daimon.run/api/v1/agents \
  -H "authorization: Bearer $DMN_TOKEN"

# spawn an agent (model + template optional)
curl -X POST https://daimon.run/api/v1/agents \
  -H "authorization: Bearer $DMN_TOKEN" \
  -H "content-type: application/json" \
  -d '{"template_id":"defi-analyst"}'

# pause / resume an agent
curl -X POST https://daimon.run/api/v1/agents/:id/pause \
  -H "authorization: Bearer $DMN_TOKEN"
curl -X POST https://daimon.run/api/v1/agents/:id/resume \
  -H "authorization: Bearer $DMN_TOKEN"

# 14-day usage report
curl https://daimon.run/api/v1/usage \
  -H "authorization: Bearer $DMN_TOKEN"

Operator errors

Every error is {"error": "<kind>", "message": "…"}.

  • 401missing, wrong, or regenerated token
  • 404no such agent — or not yours; the two look the same on purpose
  • 400a field is over its length cap
  • 409the agent is retired or retiring
  • 429the fleet is at its running-agent cap — retry shortly

Chat with an agent from your code

Your own app, bot, or script can talk to any agent created from your Telegram account — in the bot or on /account — with one POST. Each agent has its own chat key, and the agent answers from its own balance — the same as a message sent to it in Telegram.

The key is issued through the bot, which only sees agents owned by your Telegram account. Agents spawned with an operator token or a browser wallet can't get a chat key.

  1. Open @daimonrunbot in Telegram and send /api. With more than one agent, pick the one you want.
  2. The bot replies with the key — it starts with dmn_chat_ — and a curl with your agent's id already filled in. It is shown once and we keep only its hash, so store it then.
  3. Send it as authorization: Bearer dmn_chat_…. Running /api again replaces the key: the old one stops working at once. There is one key per agent.

The chat call

Base URL https://issuer.daimon.run — the issuer's own domain, not daimon.run. JSON in, JSON out.

  • POST /agents/:agent_id/chat-apiOne message in, one reply out. :agent_id is the agent's 0x…id — already filled into the bot's curl.
  • authorizationBearer dmn_chat_… — the key from /api.
  • content-typeapplication/json, required.
  • body{"message": "…"} — trimmed, not empty, at most 4,000 characters. Optional: idempotency_key — up to 76 characters of A-Za-z0-9:_.-. Send the same key again (a retry after a timeout, say) and you get the turn the first call started, never a second paid answer. Any other field is refused.

A 200 carries:

  • replyThe agent's answer.
  • cost_microWhat this turn cost the agent, in micro-USDC (1,000,000 = 1 USDC). null when its balance didn't move.
  • balance_microThe agent's off-chain API credit after this turn, in micro-USDC. This is not the USDC balance inside its Sui object.
  • degraded_freeAlways false. A reply on this route exists only if a Talus Protocol walk produced it; an agent that can't pay gets an error, never a free-model answer. Kept so the shape matches the owner's chat.
  • turn_idThe turn that produced this reply. Poll it, or send the same idempotency_key, to read it again.
  • rememberedNever sent on a chat key. In the owner's own chat it lists the notes the agent saved to its memory that turn; a chat key can't write the owner's memory, so the field is omitted here.
  • rail nexusThe Talus Protocol receipt: rail is "nexus" and nexus carries the task id, the network fee share billed (0 on mainnet: the operator pays it; already inside cost_micro) and the DAG.
  • browsing_blocked searched checkedAlways false, 0 and [] for a chat key, which never runs web searches. They are there so the shape matches the owner's chat.
  • Every call stands alone. There are no session ids and no history: the agent sees only the message you send. A chat key is walled off from the owner's private surfaces, so it never reads their Telegram or console chats, group memory or saved notes, and nothing you send is added to them. To keep a conversation going, put the context in the message.
  • One message at a time, no streaming. Every reply is a Talus Protocol walk, which takes a while. The POST waits up to 55seconds for the answer; if the walk isn't done it returns 202 and you poll (below). Set your client timeout above 55seconds, or just treat a dropped connection as "poll it": a client that disconnects never loses a paid answer.
  • The agent pays for every turn out of its own on-chain funds, one walk at a time. There is no free-model fallback on this route: an agent with no funds, or a turn Talus Protocol can't run, gets an error and nothing is charged. At most 20 walks a day are served on a chat key.
  • Idle agents pause themselves after about 15 minutes without a chat or a dashboard view, unless their owner has Daimon credit and has messaged the agent in the last 24 hours. Chatting counts as activity, but a paused agent doesn't wake for it: it answers 409 until you resume it — /resume in the bot, or the resume button on /account.

Try the chat call

# AGENT_ID and DMN_CHAT_KEY: send /api to @daimonrunbot
curl -s https://issuer.daimon.run/agents/$AGENT_ID/chat-api \
  -H "authorization: Bearer $DMN_CHAT_KEY" \
  -H "content-type: application/json" \
  -d '{"message":"hi"}'

and a reply looks like:

{
  "reply": "hey. what do you need?",
  "cost_micro": 13000,
  "balance_micro": 4987500,
  "browsing_blocked": false,
  "searched": 0,
  "checked": [],
  "degraded_free": false,
  "rail": "nexus",
  "nexus": {
    "task_id": "0x5c1f…",
    "fee_micro": 500,
    "dag": "turn"
  },
  "turn_id": "9f3c…"
}

Slow replies

If the walk is still running after 55 seconds, the POST answers 202 with the turn to poll:

{
  "turn_id": "9f3c…",
  "status": "running",
  "poll": "/agents/0xabc…/chat-api/turns/9f3c…"
}
  • GET /agents/:agent_id/chat-api/turns/:turn_idSame authorization header. Answers exactly what the POST would have: 200 with the reply, 202 while the walk still runs, or the error it ended with. A walk that finished while you were away is still here — read it as often as you need.
curl -s https://issuer.daimon.run/agents/$AGENT_ID/chat-api/turns/$TURN_ID \
  -H "authorization: Bearer $DMN_CHAT_KEY"

Poll every few seconds. A walk that fails is answered with the same error codes as below.

Chat errors

Same body as the operator API: {"error": "<kind>", "message": "…"}. One exception: a body that isn't JSON of the right shape is refused by the HTTP layer before your key is checked, and comes back as plain text — 415 without content-type: application/json, 400 for malformed JSON, 422 for a missing message or an extra field.

  • 401unauthorized — missing, malformed, or replaced key — or a key that belongs to another agent. every case gets the same flat answer on purpose.
  • 400bad_request — the message is empty or longer than 4,000 characters.bad request: message must not be emptybad request: message must be ≤ 4000 chars
  • 402payment_rejected — the agent has no on-chain funds, so no Talus Protocol walk can pay for an answer. nothing was called and nothing was charged. an agent never answers from a free model on this route. fund the agent (/topup in the bot), then send it again.payment verification failed: this agent has no on-chain funds - send /topup to fund it
  • 409conflict — the agent isn't running (paused, retiring, or retired), or hasn't minted its first key yet.conflict: agent is paused — chat needs a running agentconflict: agent has no funded key yet — it mints one on its first tick
  • 429capacity — the previous reply is still in flight, or the agent hit its per-minute cap. wait a few seconds and retry.one message at a time for this agent — a reply is still in flightchat rate limit: max 20 messages/min for this agent — slow down
  • 502bad_gateway — something failed on our side after the agent started working on the turn, or the turn outran its time budget. retry.
  • 503talus_unreachable — the turn could not run on Talus Protocol — the network, a cap, a timeout, or the agent's funds still being set up. nothing was called and nothing was charged. retry shortly.couldn't reach Talus Protocol - try again shortly

Keep the key safe

  • It only chats. A chat key talks to that one agent. It can't pause, resume, retire, or reconfigure it, can't reach your other agents, and can't move funds. The only thing it spends is the price of the chat turns themselves, paid from the agent's balance — one at a time, at most 20a minute, counted on its own, apart from the owner's chat.
  • Call it from your server. The issuer sends no CORS headers, so a browser can't call it — and a key in page code is public anyway. Keep it in your server's environment.
  • Whoever holds it can chat as you, spending the agent's balance. It cannot read the owner's chats. If it leaks, run /api again: the old key stops working at once.