The async query model
This is the one concept every integrator needs before calling anything under /api/queries.
Two possible responses
POST /api/queries/{id}/refresh (ad-hoc cache-or-enqueue) can return either:
-
an immediate result, already available:
{ "query_result": { "id": 501, "data": { "...": "..." }, "runtime": 0.42 } } -
or a freshly enqueued job, because the result needed a new run:
{ "job": { "id": 9001, "status": 1, "query_result_id": null } }
Which one you get depends on whether a fresh run was actually needed — you don’t choose, and your
code needs to branch on the response shape (presence of "query_result" vs "job").
If you get a job: poll it
Poll GET /api/jobs/{id} until status reaches a terminal value:
status |
Meaning |
|---|---|
1 |
Pending |
2 |
Started |
3 |
Success |
4 |
Failure |
5 |
Cancelled |
[!TIP]
1and2are the only non-terminal states — stop polling as soon as you see anything else.
Once it succeeds: fetch the result
When status is 3 (Success), the job response includes a query_result_id. Fetch the actual
data with:
GET /api/query_results/{query_result_id}
Sequence, end to end
POST /api/queries/{id}/refresh(orrun, see the Queries resource).- If the response has
"query_result", you’re done — that’s the data. - If it has
"job"instead, pollGET /api/jobs/{id}untilstatusis3,4, or5. - On
3, fetchGET /api/query_results/{query_result_id}for the data. On4or5, the run failed or was cancelled — there’s no result to fetch.