Query API
Read your own Morse data from a program: pull traces into a warehouse, feed spend into a BI tool,
or run a nightly report. Six read-only REST endpoints under /api/v1/query/, authenticated with an
API key.
How it works
Auth
Send an API key as a bearer token:
Authorization: Bearer mhq_…Browser sessions are not accepted. Use a read-only personal key for scripts and BI tools: create one on your Profile page and choose Access → Read-only. A read-only key can query data but is refused (403) by every endpoint that sends data in, so a leaked reporting key cannot write to your workspace. Full-access personal keys and environment keys also work here.
Every result is scoped to the organization the key belongs to.
Endpoints
| Endpoint | Returns |
|---|---|
GET /api/v1/query/traces | Traces in a time window, newest first, paginated |
GET /api/v1/query/traces/{trace_id} | One trace with its spans (up to 2,000) and their inputs/outputs |
GET /api/v1/query/agents | Your agents |
GET /api/v1/query/agents/{agent_id}/stats | Daily runs, success rate, cost, latency and tokens for an agent |
GET /api/v1/query/cost/breakdown | Spend grouped by agent, model, or any user_metadata key |
GET /api/v1/query/evals/scores | Eval scores in a time window, newest first, paginated |
Parameters
| Endpoint | Parameters |
|---|---|
traces | since, until, agent (name or id), status, limit, cursor |
agents/{id}/stats | days: 1, 7, 30 or 90 (default 7) |
cost/breakdown | group_by: agent (default), model, or a user_metadata key; since, until |
evals/scores | since, until, agent, scorer, limit, cursor |
status is one of running, completed, failed, timed_out.
Response fields
- Trace:
trace_id,agent_id,agent_name,environment,status,started_at,ended_at,duration_ms,success,outcome,error_message,total_tokens,total_cost_usd,span_count,thread_id,user_id,user_metadata. - Trace detail adds
spansandspans_truncated. Each span:span_id,parent_span_id,type,name,status,started_at,ended_at,duration_ms,model,input_tokens,output_tokens,total_tokens,cached_input_tokens,cost_usd,error_message,input,output. Inputs and outputs are returned as stored, after your redaction rules. - Agent:
agent_id,name,created_at. - Agent stats:
agent_id,agent_name,days, anddailyrows ofdate,runs,success_rate,cost_usd,avg_duration_ms,total_tokens. - Cost breakdown:
group_by,since,until, anddatarows ofkey,cost_usd,trace_count,total_tokens, highest cost first. - Eval score:
id,trace_id,span_id,agent_id,scorer_key,scorer_version,scorer_type,score,label,reasoning,created_at.
New fields may be added; your code should ignore fields it doesn’t recognise. Existing fields are
never renamed or removed within /api/v1/.
Errors return {"detail": "…"}: 400 for a bad parameter, 401 without a valid key, 403 for a
key without read access, 404 for a trace or agent outside your organization.
Time windows
since takes an ISO-8601 datetime or a relative window such as 24h or 7d (default 24h).
until takes an ISO-8601 datetime (default now).
Pagination
List endpoints return {"data": [...], "next_cursor": "…"}. Pass next_cursor back as cursor
to get the next page; it is null on the last page. limit is 1–500 (default 100). Walking every
page returns each record in the window exactly once.
Rate limits
1,000 requests per hour per key. Responses carry X-RateLimit-* headers; over the limit you get
429 with Retry-After.
Morse’s own probe traffic is excluded, so totals match the dashboard.
How to use it
Pull yesterday’s traces for one agent, page by page:
curl -H "Authorization: Bearer $MORSE_API_KEY" \
"https://api.morsehq.dev/api/v1/query/traces?agent=support-bot&since=24h&limit=500"Spend per customer over the last 30 days (requires customer_id in your trace metadata):
curl -H "Authorization: Bearer $MORSE_API_KEY" \
"https://api.morsehq.dev/api/v1/query/cost/breakdown?group_by=customer_id&since=30d"Traces without the key are grouped under "key": null.
Related
- MCP — the same data for AI assistants such as Claude Code and Cursor.
- OTLP integration — the other direction: getting data in.