API Reference›Results
API Reference

Results

Retrieve persisted query results. Every query execution persists its results asynchronously. Results transition through statuses: processing → ready (or failed). Once ready, the full result data can be retrieved by ID.

List results

GET/v1/results

List stored results for the database named by the required X-Database-Id header.

Query parameters

  • limit integer — Maximum number of results (default: 100, max: 1000)
  • offset integer — Pagination offset (default: 0)

Headers

  • X-Database-Id string — required. Database to scope the results to (required)

Response 200 — List of results

  • count integer — required. Number of results returned in this response. Min: 0
  • has_more boolean — required. Whether there are more results available after this page
  • limit integer — required. Limit used for this request. Min: 0
  • offset integer — required. Pagination offset used for this request. Min: 0
  • results ResultInfo[] — required
    • created_at string — required
    • error_message string,null
    • id string — required
    • status string — required
{
  "count": 0,
  "has_more": true,
  "limit": 0,
  "offset": 0,
  "results": [
    {
      "created_at": "2026-01-01T00:00:00Z",
      "error_message": "string",
      "id": "string",
      "status": "string"
    }
  ]
}

Errors

StatusDescription
400Missing or malformed X-Database-Id header
404Database not found

Get result

GET/v1/results/{id}

Retrieve a persisted query result by ID. The response format for the ready state is selected by Accept header or ?format= query param; non-ready states use the same status codes and JSON body shape regardless of format.

Result statusStatus × body
ready + JSON200 application/json — GetResultResponse with columns, rows, etc.
ready + Arrow200 application/vnd.apache.arrow.stream — schema, RecordBatches, EOS
ready + CSV200 text/csv; charset=utf-8 — single header row, streamed batch-by-batch
ready + Markdown200 text/markdown; charset=utf-8 — GitHub-flavored pipe table, streamed
ready + Parquet200 application/vnd.apache.parquet — raw parquet bytes (no conversion)
pending/processing202 application/json {status, result_id} + Retry-After
failed409 application/json {status, result_id, error_message}
not found404 application/json (ApiErrorResponse)

?format= accepts arrow, json, csv, md, parquet and takes precedence over Accept. markdown is accepted as a runtime alias for md. Use ?offset=N&limit=M to slice the result; offset defaults to 0 and limit is unbounded by default. Both must be non-negative; invalid values return 400. When a finite limit doesn't reach the end of the result, a Link header with rel="next" points at the following page. ?offset/?limit are ignored for format=parquet since that path returns the underlying file unchanged.

JSON is the only format with a size limit. Building a JSON body requires holding the whole slice in memory at once, so a request whose JSON body would exceed the instance's per-fetch memory budget is refused with 413 and the error code RESULT_TOO_LARGE, and a request that would push the total across concurrent JSON fetches over that budget is refused with 429. If the result's size cannot be determined at all, the fetch is refused with 503 rather than served unchecked. None of the three returns partial data. To read a result of any size, request it as ?format=arrow, csv, md, or parquet — those stream and are never size-limited. Paging with offset/limit is not an alternative: the rows come back in no guaranteed order, so pages are not a reliable way to read one result in parts.

Ready responses (Arrow, CSV, Markdown, JSON) carry X-Total-Row-Count (the full result row count, independent of offset/limit); the JSON body repeats it as total_row_count, so a client that cannot read response headers can still compare it against row_count to tell a complete result from a windowed one. Responses are streamed end-to-end, so a client can disconnect at any time and the server stops reading.

IEEE special floats (±Inf, NaN) have no canonical JSON representation. For cross-format consistency the JSON, CSV, and Markdown paths emit them as null / empty cells, and JSON nullable[] is widened to match. The Arrow IPC and Parquet bodies are binary round-trip formats and preserve the raw IEEE values; callers cross-checking a result across CSV and Parquet should not byte-compare those slots.

Path parameters

  • id string — required. Result ID

Query parameters

  • offset integer — Rows to skip (default: 0)
  • limit integer — Maximum rows to return (default: unbounded)
  • format ResultsFormatQuery — arrow, json, csv, md, or parquet — overrides the Accept header. markdown is also accepted at runtime as an alias for md.

Headers

  • X-Database-Id string — required. Database the result belongs to (required)

Response 200 — Result data. The body depends on the negotiated format: JSON callers receive GetResultResponse; Arrow callers receive an Arrow IPC stream; CSV callers receive comma-separated text (LF-terminated, double-quote escaped, RFC 4180-style quoting but not RFC 4180-strict on line endings); Markdown callers receive a single GitHub-flavored pipe table; Parquet callers receive the raw parquet bytes, served as-is. Non-finite floats (±Inf, NaN) render as null (JSON) or empty cells (CSV, Markdown) for cross-format consistency. Accept is treated as a flat content-type list — q= quality values are ignored; use ?format= to disambiguate.

  • columns string[] | null
  • error_message string,null
  • nullable boolean[] | null
  • result_id string — required
  • row_count integer,null
  • rows any[][] | null — Array of rows, where each row is an array of column values.
  • status string — required
  • total_row_count integer,null — Grand total rows in the full result, ignoring offset and limit. Present whenever the result is ready, and carrying the same value as the X-Total-Row-Count response header. Compare it against row_count to tell whether this body is the whole result: row_count < total_row_count means the rest is still there, one page further on. Without it a windowed fetch cannot tell a full result from a truncated one from the body alone.
{
  "columns": [
    "string"
  ],
  "error_message": "string",
  "nullable": [
    true
  ],
  "result_id": "string",
  "row_count": 0,
  "rows": [
    [
      null
    ]
  ],
  "status": "string",
  "total_row_count": 0
}

Response 202 — Result is still being computed (pending or processing). Poll the same URL.

  • columns string[] | null
  • error_message string,null
  • nullable boolean[] | null
  • result_id string — required
  • row_count integer,null
  • rows any[][] | null — Array of rows, where each row is an array of column values.
  • status string — required
  • total_row_count integer,null — Grand total rows in the full result, ignoring offset and limit. Present whenever the result is ready, and carrying the same value as the X-Total-Row-Count response header. Compare it against row_count to tell whether this body is the whole result: row_count < total_row_count means the rest is still there, one page further on. Without it a windowed fetch cannot tell a full result from a truncated one from the body alone.
{
  "columns": [
    "string"
  ],
  "error_message": "string",
  "nullable": [
    true
  ],
  "result_id": "string",
  "row_count": 0,
  "rows": [
    [
      null
    ]
  ],
  "status": "string",
  "total_row_count": 0
}

Errors

StatusDescription
400Invalid offset, limit, or format.
404Result not found.
409Result computation failed. Body carries error_message describing the failure.
413The requested slice is too large to return as JSON (error code RESULT_TOO_LARGE). No partial data is returned. Retrying the same request will fail again; request the result as ?format=arrow, csv, md, or parquet instead, which stream and have no size limit. JSON only.
429Concurrent JSON fetches have already committed the instance's per-fetch memory budget. Transient — retry shortly, or request the result in a streaming format, which has no size limit. JSON only.
503The result's size could not be determined, so it could not be checked against the memory budget and was not served. Transient — retry shortly, or request the result in a streaming format, which needs no size check. JSON only.