Compile one query from the dictionary and answer with its rows
Hand this the query the dictionary describes and it answers with rows, the columns, the formats each figure prints in, the window it actually ran over and the query itself, echoed back.
A POST THAT WRITES NOTHING, and it costs metrics:read for that reason. The body is a question, not a change: the query is a nested object and a URL is the wrong place for one. Every statement it compiles is a SELECT on the read replica, and every value in the body reaches it as a bound parameter. There is no field for a table, a column or a fragment, and an unknown key is refused by name rather than ignored.
THE FIGURES ARE THE PAGE'S FIGURES. The query is resolved against the same catalog get_metric_dictionary publishes and compiled by the same compiler the Sales page reads through, so a warehouse job pulling net sales for a week gets the week the page shows, to the cent.
time_range may be absolute or relative. A relative window is echoed back as it was asked and resolved_time_range carries the two dates it ran over, because the rows carry buckets and a bucket is an opening date, not a bound. computed_as_of appears where a domain serves derived figures and there is a real stamp to report; a projection with none says nothing rather than inventing "now".
Send {"query": {...}}, or the query object at the top level. Both are read, because the query travels in a query field on every answer here and a caller feeding one back should not have to know which spelling to unwrap it into.
Scope: metrics:read.
Request
- Base URL: https://api.app.tightly.io
- URL: https://api.app.tightly.io/api/v1/metrics/query
- Auth: HTTP bearer
Headers
The date train to answer on. One train exists today, 2026-11, the one this reference describes and the one every key is minted on, so the call answers on it with or without this header. Send it anyway, so a client built now names its train from the start.
A string of your own, up to 255 characters, that makes this write safe to retry. Send the same key twice and the second request is answered with the first one's status and body instead of writing again, so a client that retried after a timeout ends holding the record's id rather than creating a second one. Reusing a key with a different body, or while the first request is still running, is refused 409. A write that failed releases its key. Keys answer for 24 hours and belong to the API key that used them. A key longer than 255 characters is ignored and the write goes ahead without the guarantee.
Request body
Response
The rows, and the question that produced them
Changes
No recorded changes to this operation across all 1 revision of this API.