Skip to main content
The Halyrd API is a local HTTP service exposed by the Python FastAPI backend that ships with your Halyrd installation. Because the agent runs entirely on your machine, the API is bound to localhost — you talk to it directly from your own code, scripts, or dashboard without routing through any external server. All agent resources live under /agents/{id}/…, and the single running agent is always reachable via the canonical alias /agents/current.

Base URL

http://localhost:8000
The FastAPI backend starts automatically when you launch Halyrd. Every path in this reference is relative to that base URL.

Authentication

The API runs on localhost for a single user. No API token, header, or session cookie is required in the current version. If you ever expose the API beyond localhost — for example, through a reverse proxy — you should add your own authentication layer at that boundary.

Content-Type

All requests and responses use application/json. Set the Content-Type: application/json header on any request that includes a body.

Agent path conventions

Every agent resource follows the pattern /agents/{id}/…. For the single running agent you can use either its literal ID (seed) or the stable alias current — both resolve identically.
/agents/current           ← always the running agent
/agents/seed              ← same agent, by explicit ID
/agents/current/equity    ← equity history for the running agent
/agents/current/trades    ← trade history
The path is plural (/agents/) even though only one agent runs today. The schema is designed for a future multi-agent fleet — using /current keeps your integration forward-compatible.

Transport model

Halyrd splits its data across two transports so you always have the right tool for the job.
TransportUse for
RESTInitial page load, historical data, config reads, and mutations (promote / demote / kill-switch)
WebSocketLive streaming data — equity snapshots, trades, journal entries, risk vetoes, and status changes
Use REST to seed your UI with history and to issue commands. Subscribe to the WebSocket to receive every new event as soon as it happens. See WebSocket for full event payloads.

Health check

Verify the backend is running before making any other requests.
GET /health
Response
{
  "status": "ok"
}

Quick example

Fetch the current agent’s status and phase:
curl http://localhost:8000/agents/current
{
  "id": "seed",
  "name": "Halyrd",
  "status": "PAPER",
  "phase": "paper",
  "market_mode": "spot"
}

TypeScript types

TypeScript types are available in the @repo/api-types package. Import them directly in your frontend or integration code:
import type { AgentStatus, EquitySnapshot } from '@repo/api-types';

// AgentStatus: "PAPER" | "ELIGIBLE" | "LIVE" | "DEMOTED"
// EquitySnapshot: { ts: string; equity: number; phase: "paper" | "live"; dd_from_peak: number; }

Error codes

When an operation fails, the API returns a JSON body containing a code field alongside the HTTP status. Use the code field — not just the HTTP status — to drive your error handling logic, since multiple distinct situations share the same 422 status.
CodeHTTP StatusWhenWhat to do
RISK_VETO422Policy layer blocked a tradeCheck risk objectives; the journal shows which rule fired
QUOTE_DIVERGENCE422Quote too far from CMC mid priceRetry; the skip is journaled automatically
QUOTE_STALE422Quote or block is too oldRetry after a short delay
INSUFFICIENT_LIQUIDITY422Insufficient liquidity for the trade sizeReduce position size or choose a more liquid token
MARKET_MODE_MISMATCH422StrategySpec mode ≠ executor modeCheck the market_mode field in your spec
TWAK_BLOCK422Signing layer refused the transactionCheck allowlist, per-trade cap, and daily cap
NOT_ELIGIBLE409Promote attempted without ELIGIBLE statusUse force-promote with explicit confirmation
DEMOTED409Agent is currently demotedWait for reset or re-approve in Settings
TWAK_BLOCK only occurs in live mode. In paper mode, the signing layer is not involved, so all 422 errors come from the policy or quote layers.

REST endpoint reference

The table below lists every REST endpoint. Build-now endpoints are available in the current release; roadmap endpoints are designed and reserved but not yet implemented.
MethodPathResponseNotes
GET/health{ status: "ok" }Backend health check
GET/agentsAgent[]Returns an array of length 1 today
GET/agents/{id}Agentid, name, status, phase, market_mode, last_heartbeat
GET/agents/currentAgentAlias — always resolves to the running agent
GET/agents/{id}/equityEquitySnapshot[]Query params: from, to, interval
GET/agents/{id}/tradesTrade[]Query param: phase=paper|live|all
GET/agents/{id}/journal{ entries[], next_cursor }Cursor-paginated; query params: cursor, limit
GET/agents/{id}/evaluationEvaluation state + objectivesstate, objectives[], window_days_elapsed, trade_floor, eligible
GET/agents/{id}/risk/objectivesObjective[]rule, current, limit, headroom_pct per objective
GET/agents/{id}/risk/blocksBlock[]ts, layer, rule, reason, order_ref per block
GET/agents/{id}/watchlist/candidatesRanked candidates + recommended presets
PUT/agents/{id}/watchlistNew ConfigVersionCommits watchlist selection
GET/agents/{id}/config/versionsConfigVersion[]id, parent_id, params_summary, run_period, outcome
POST/agents/{id}/promote{ status: "LIVE", first_tx_hash }Pass { force: true } to bypass NOT_ELIGIBLE guard
POST/agents/{id}/demote{ status: "PAPER" }
POST/agents/{id}/kill-switch{ twak_session: "revoked" }Requires { confirm: true } in body
PATCH/agents/{id}/configNew ConfigVersionBody: evaluation_config_patch
GET/agents/{id}/identityERC-8004 identity fieldsRoadmap
POST/agentsNew AgentRoadmap — multi-agent spawn
POST/backtests{ backtest_id }Roadmap
GET/backtests/{id}Backtest result + gate statusRoadmap
GET/indicatorsIndicator[]Roadmap