---
title: "Run a structured query"
method: POST
path: "/query"
tags: ["Query"]
---

# Run a structured query

`POST /query`

## Request

- Base URL: `https://api.cloudglue.dev/v1`
- URL: `https://api.cloudglue.dev/v1/query`
- Auth: HTTP bearer

Run a synchronous read-only SQL query over the structured data extracted from one or more collections. Queries execute against three virtual tables — files, entities, and segment_entities — built from each file's most recent completed extraction.

Each query costs 2 credits. Results are returned inline and stored, so completed runs can be re-fetched via GET /query/{id}. Use GET /query/schema to discover the queryable tables and per-collection fields.

## Request body

- RunQueryRequest
  - `collections` string[], required: Collection IDs to query over. All collections must belong to your account; face-analysis collections are not supported.
  - `sql` string: A single read-only SQL SELECT statement over the virtual tables (files, entities, segment_entities). Exactly one of sql or query must be provided.
  - `query` string: A natural-language question to run instead of sql. Cloudglue compiles it to SQL against the same virtual schema, runs it, and returns the compiled statement in the response's sql field. Exactly one of sql or query must be provided. Costs 4 credits (refunded if compilation fails); returns 422 if it cannot be compiled.
  - `format` 'json' | 'csv' | 'jsonl': Result format. 'json' returns rows inline (synchronous). 'csv' and 'jsonl' are for background exports only and require background: true.
  - `max_rows` integer: Maximum number of result rows to return inline. Results with more rows are truncated (truncated: true). Does not apply to background exports, which stream the full result.
  - `background` boolean: When true, run the query as a background export: the full result streams to a gzipped csv/jsonl file and the response returns immediately with status 'in_progress' and an id to poll. Requires format 'csv' or 'jsonl'. Reserves 4 credits, reconciled to +1 per 100MB of compressed output. Cannot be combined with dry_run.
  - `dry_run` boolean: When true, validate (and, for a natural-language query, compile) the statement and return the effective SQL plus its output column schema without executing it over any data. No rows are produced and it is billed at a reduced rate. Cannot be combined with background.

## Response `200`

Query executed successfully

- QueryResult
  - `id` string, uuid: Query result ID
  - `object` 'query_result': Object type identifier
  - `status` 'completed' | 'failed' | 'in_progress' | 'cancelled': Current status of the query. Synchronous queries return 'completed' or 'failed'.
  - `created_at` number: Unix timestamp of when the query was created
  - `collections` string[]: Collection IDs the query ran over
  - `sql` string, nullable: The effective SQL that was executed (echoes the request's sql)
  - `columns` object[], nullable: Result columns in select order
    - `name` string: Column name
    - `type` string: SQL type of the column
  - `rows` object[], nullable: Result rows as objects keyed by column name
  - `row_count` integer: Number of rows returned
  - `truncated` boolean: Whether the result was truncated by max_rows or the stored-result size cap
  - `dry_run` boolean: True when the query was only validated/compiled (dry_run request): columns holds the output schema and rows is null.
  - `usage` QueryUsage
    - `files_scanned` integer: Number of files loaded into the files virtual table
    - `entity_rows` integer: Number of rows loaded into the entities virtual table
    - `segment_entity_rows` integer: Number of rows loaded into the segment_entities virtual table
    - `engine_ms` number: SQL execution time in milliseconds
    - `total_ms` number: Total processing time in milliseconds, including dataset preparation
  - `error` object, nullable: Error details if the query failed
    - `code` string
    - `message` string
  - `format` 'json' | 'csv' | 'jsonl', nullable: The result format ('csv'/'jsonl' for background exports)
  - `download_url` string, nullable: Signed URL to download a completed background export. Valid for 24 hours and not refreshed on read (re-run the export if it expires); null for synchronous runs and until a background export completes
  - `download_expires_at` number, nullable: Unix timestamp (ms) when download_url expires
  - `output_bytes` integer, nullable: Compressed size of a completed background export, in bytes

## Other responses

- `400`: Invalid request parameters or rejected SQL (multiple statements, a non-SELECT statement, SQL that could not be parsed, or a face-analysis collection in scope)
- `402`: Insufficient credit balance
- `404`: One or more collections not found
- `408`: Query exceeded the execution time limit
- `409`: The selected collections exceed the maximum queryable dataset size
- `422`: A natural-language query could not be compiled into valid SQL — refine the question or send sql directly
- `429`: Too many concurrent queries, or the per-minute rate limit was exceeded
- `500`: An unexpected error occurred on the server

## Changes

- **2026-10-30** `23d3f240819f`: 8 info
  - added the optional property `code` to the response with the `400` status
  - added the optional property `code` to the response with the `402` status
  - added the optional property `code` to the response with the `404` status
  - added the optional property `code` to the response with the `408` status
  - …4 more
- **2026-08-02** `a7a390d80571`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/cloudglue/apis/cloudglue-api/changes/query/post.md)

---

[API](https://skmtc.dev/cloudglue/apis/cloudglue-api.md) - [All operations](https://skmtc.dev/cloudglue/apis/cloudglue-api/llms.txt) - [OpenAPI document](https://skmtc.dev/cloudglue/apis/cloudglue-api/revisions/23d3f240819f?raw)
