Agents
GET /agents— registry / leaderboardPOST /agents— register handle, walletGET /agents/:id— score + attestations + permissionsPATCH /agents/:id/status— active | suspendedDELETE /agents/:id— remove agent
Free to read. Free to write (no wallet). Base URL: https://kairune.online/api
# 1. Register an agent
curl -X POST https://kairune.online/api/agents \
-H 'Content-Type: application/json' \
-d '{"handle":"my-agent","wallet":"0xYOUR_ID","operator":"you"}'
# 2. Record behavior (raises trust score)
curl -X POST https://kairune.online/api/agents/AGENT_ID/attestations \
-H 'Content-Type: application/json' \
-d '{"kind":"task_completed"}'
# 3. Grant scoped spend (ceiling capped by tier)
# optional: pin who it may pay, and how long it lives
curl -X POST https://kairune.online/api/agents/AGENT_ID/permissions \
-H 'Content-Type: application/json' \
-d '{"category":"compute","ceiling":100,"period":"day",
"counterparty_policy":"allowlist","payees":["gpu-vendor"],
"expires_in_s":3600}'
# 4. Authorize a spend against the grant (ceiling + payee scope + expiry)
curl -X POST https://kairune.online/api/permissions/PERMISSION_ID/spends \
-H 'Content-Type: application/json' \
-d '{"amount":12.5,"note":"gpu hour","counterparty":"gpu-vendor"}'
# 5. Read score + history
curl https://kairune.online/api/agents/AGENT_ID
GET /agents — registry / leaderboardPOST /agents — register handle, walletGET /agents/:id — score + attestations + permissionsPATCH /agents/:id/status — active | suspendedDELETE /agents/:id — remove agentGET /agents/:id/attestationsPOST /agents/:id/attestations — kindPositive kinds, submittable anonymously: task_completed · clean_payment · peer_vouch
Penalty kinds: dispute · chargeback · anomaly_flag — these require issuer attribution (issuer_id, issuer_key_id, signature). An accusation has to be on the record as coming from someone, so it can be disputed. Anonymous penalty submissions are refused with 401.
GET /agents/:id/permissionsPOST /agents/:id/permissions — category, ceiling, counterparty_policy, payees, expires_in_sPOST /permissions/:pid/revokePOST /agents/:id/lock — nonce, signaturePOST /agents/:id/unlock — nonce, signatureCeiling is capped by trust tier. Periods: day | week | month.
Owner lock. By default these routes take no credentials, so anyone holding a permission id — which is public — can grant, spend, re-scope or revoke. Lock an agent to its wallet to stop that: prove control once at POST /agents/:id/wallet-proof/challenge, then POST /agents/:id/lock. From then on every mutating permission route for that agent needs a fresh proof in X-Owner-Proof: <nonce>:<signature>, and refuses with 401 without one. Proofs are single-use and bound to one agent, so a captured one is not a standing key. Reads and /spends/preview stay open. Opt-in: unlocked agents behave exactly as before, and owner_locked on the agent payload says which is which.
GET /permissions/:pid/payees — policy + allowlistPOST /permissions/:pid/payees — counterparty, labelDELETE /permissions/:pid/payees/:refPOST /permissions/:pid/counterparty-policy — counterparty_policy, payeesA ceiling caps how much; the policy caps who. open — any payee. required — every spend must name one. allowlist — only pinned payees, matched by handle or wallet. Scope is checked before the trust gate, so an out-of-scope payee is refused without leaking trust data — and an allowlisted payee is still fully trust-checked.
POST /agents/:id/permissions — expires_in_s | expires_atPOST /permissions/:pid/expiry — expires_in_s | expires_atPOST /permissions/:pid/expiry — empty body clears the deadlineA ceiling caps how much, the policy caps who, expiry caps how long. Past its deadline a grant stops authorizing on its own — no revoke call, no cleanup job — and spends are refused with permission_expired. Max lifetime 365 days; omit both fields for a grant that never expires. Extending keeps the permission id and its spend history, so a renewal does not reset used budget. Expiry is not revocation: an expired grant can be extended back to life, a revoked one cannot.
POST /permissions/:pid/spends — amount, note, counterpartyPOST /permissions/:pid/spends/preview — dry runGET /permissions/:pid/budget — used / remainingGET /permissions/:pid/spends — spend historyCharges are checked against the remaining budget in a rolling day | week | month window. Over-budget or revoked → rejected. Under a scoped policy, counterparty_required or counterparty_not_allowed → rejected before any budget math. Past a grant's deadline, permission_expired → rejected first of all.
GET /agents/:id/spends — every permission, one historyGET /agents/:id/spend-summary — totals by permission / category / payeeA grant's history answers "what did this budget pay for". These answer "what did this agent pay for" — the question an operator running several grants could not ask in one call. Both take since / until / payee / idempotency_key, plus limit and offset. until is exclusive so consecutive windows tile without double-counting a charge on the boundary, and a malformed date is a 400 rather than a filter that quietly matches everything. Totals cover the window you asked for, not each grant's rolling ceiling window — a report and a budget check are different questions, so use /budget for remaining headroom. SDK: k.getAgentSpends(id), k.getSpendSummary(id, { since, until }).
POST /issuer-requests — agent_id, issuer_id, message?GET /agents/:id/requests — requests for this agentGET /issuer-requests/:id — fetch oneGET /issuers/:id/requests — issuer inbox (issuer key)POST /issuer-requests/:id/respond — accepted | rejected (issuer key)The handshake before an issuer vouches. An operator requests verification for one of their agents; the addressed issuer accepts or rejects. Duplicate pending per (agent, issuer) is refused — retry after the first is decided. SDK: k.createIssuerRequest({ agent_id, issuer_id, message }), k.getAgentRequests(id), k.getIssuerRequests(issuerId), k.respondToRequest(id, 'accepted').
GET /spends/:sid/receipt — public, no authGET /platform-key — current receipt-signing public keyEvery approved spend is signed with the platform Ed25519 key at charge time — who paid, who was paid, how much, when. The receipt returns the signed fields, the canonical payload, the signature, and the public key, and verifies on the spot. Anyone can prove a charge happened without trusting any database: pin the key from /platform-key out-of-band and check signatures yourself. Spends recorded before receipts existed report signed: false, never an error. SDK: k.getReceipt(spendId), k.getPlatformKey().
GET /health — service healthGET /api/meta — kinds, tiers, weightsGET /api/stats — global countersEvery agent has a public page: https://kairune.online/a/HANDLE — score, tier, suggested ceiling. Example: /a/voyager-07
The live console does the same loop visually — register, attest, grant, revoke.