Query API

Embed
Preview of the card
<a href="https://forumulate.com/p/watchtower/docs/query"><img src="https://forumulate.com/api/public/orgs/watchtower/spaces/docs/pages/93c62b97-2daa-4bc4-8d7e-260ffaaf713e/social-card.svg?v=3e7ae33eec8b" alt="Query API" width="600" height="315"></a>

Every query route is project-scoped under /v1/projects/{prj}, needs a session or API credential with read access, and returns 404 (never 403) when the project is not visible to the caller. Errors are RFC 9457 application/problem+json. Try any route in the web app under API, or from the published openapi.json (GET /openapi.json).

Route

Purpose

POST /logs/search, /logs/histogram, /logs/fields, GET /logs/tail

log search, volume buckets, field discovery, live tail

POST /traces/search, GET /traces/{trace_id}

trace search and one trace's spans

GET /metrics/names, /metrics/labels, /metrics/labels/{name}/values, /metrics/cardinality

metric catalog

GET /metrics/query_range, /prometheus/api/v1/query, /prometheus/api/v1/query_range

PromQL (range and instant)

POST /query/sql, /query/search

tenant-safe SQL and Lucene/KQL over logs and spans

GET /query-history

the caller's last 100 queries

Query languages: see the pages in docs/product/query/ (pipe, lucene-kql, traces, functions).

Pagination

List and search routes take limit and cursor (query string, or JSON body for POST searches) and answer {data, next_cursor}. Pass next_cursor back unchanged; null ends the list. Cursors are opaque and tied to the query that produced them.

Budgets

Each statement runs under a per-query memory and thread limit and one time budget. On the SQL route (query/sql) and the query routes that compile to it, a project may run 4 statements at once and the platform 8; beyond that the answer is 429. Time ranges are clamped to the project's retention for the signal and to 31 days. A result over 64 MiB gives 422 result too large; narrow the range or add a limit. Syntax errors give 422 with an offset and never echo the query text.

Partial results

When a scan cap is hit (for example 10,000 candidate traces or 1,000 spans per trace) the response still succeeds and says so: truncated: true on a result, spans_truncated: true on a trace with too many spans, partial: true in a trace summary when spans are missing. Counts from a truncated result are lower bounds. Clients must surface the flag instead of treating the result as complete. Delivery is at-least-once, so the newest window can briefly lack rows that are still in flight.

Example

curl -sS -X POST "$WT_API/v1/projects/$PRJ/logs/search" \
  -H "Authorization: Bearer $WT_TOKEN" -H 'Content-Type: application/json' \
  --data '{"q":"severity:error","limit":50}'
Updated