/btql endpoint runs SQL over your logs, experiments, and datasets and returns the rows in the response. If a query times out, try narrowing it first (see SQL best practices). For large exports, or a well-scoped query that still times out, use an async query.
Base URL
The base URL depends on your organization’s data plane region:
Authenticate every request with your API key in the
Authorization header. The examples below use the US base URL.
Query data
Send aPOST /btql request with a SQL query in the body.
Braintrust runs the query synchronously and returns the results in a single response.
Example
For correct day boundaries, set
tz_offset to match your timezone. For example, use 480 for US Pacific Standard Time.fmt:
json(default): an object with adataarray of row objects. Each row contains the columns your query selects, or every column forSELECT *.jsonl: one row per line, for streaming.parquet: a binary column format, suited to large exports.
JSON
To fetch more rows than fit in one response, see Pagination.
Pagination
Each response returns one page of rows. To fetch every page:- Run the query, and read the cursor from the
x-bt-cursorresponse header. - Resend the same query with the cursor:
- SQL string: append
OFFSET '<cursor>'. See Syntax styles. - Structured query object: set its
cursorfield.
- SQL string: append
- Repeat until a response has no cursor.
On Braintrust-hosted deployments, large responses redirect to a stored copy of the results. Follow the redirect (for example, with
curl -L), and read the cursor from the x-amz-meta-bt_cursor header instead.SELECT * FROM dataset(...).
If you use the Python or TypeScript SDK to read a dataset or experiment, you don’t need this code. Iterate over the dataset or experiment, and the SDK handles the cursor for you.
Timeouts
On Braintrust-hosted deployments, synchronous queries time out after 30 seconds. That’s enough for interactive queries, dashboards, and most routine reads. If a query times out, try optimizing it first. For large exports, or a well-scoped query that still times out, use an async query.Examples
Export data
Export data
This example exports up to 100 traces from the last 7 days of a project’s logs to
export.json and export.parquet. You can export logs, experiments, or datasets to JSON or Parquet by setting fmt.Each request returns one page of results. Without a LIMIT, a project_logs() query returns the first 10 rows, or 10 traces with shape => 'traces', and other sources return the first 1,000. To export more, follow the x-bt-cursor header as described in Pagination.Fetch experiment results
Fetch experiment results
This example checks how much of an experiment has been reviewed. It returns a single row with two counts:
reviewed, the number of rows with a value in your review score column, and total, the number of root spans, one per test case. Replace response quality with the name of your review score. You can adapt the query to check other experiment metrics.Fetch child spans by trace metadata
Fetch child spans by trace metadata
This example measures how long a particular step takes across traces that share a metadata value. It retrieves up to 10 traces whose metadata matches, including all of their child spans, then keeps the spans with a given name and prints each span’s duration and the average, in seconds. Replace
your-org-name with the metadata value to match, and your-span-name with the name of the span to measure.Async queries
Async queries are only available on the Enterprise plan.
- A large export or backfill that returns many thousands of rows.
- A well-scoped query that still times out as a synchronous request.
count(), sum(), GROUP BY, SELECT DISTINCT, ORDER BY, and OFFSET aren’t supported.
Async queries address request timeouts and long runtimes. They aren’t a substitute for query optimization, so narrow a broad query before running it asynchronously. See SQL best practices.
Limits
Braintrust-hosted- Runtime: 1 hour of cumulative runtime.
- Result size: 10 GiB.
- Retention: 7 days. Fetch the results within that window.
- Requirements: data plane v2.3.0 or later (Helm chart 6.4.0 or later). If you deploy with the AWS Terraform module, use v6.0.0 or later and set
enable_ecs_api = true. With the default setting, the async endpoints aren’t reachable. - Runtime: 1 hour of cumulative runtime by default.
- Result size: 200 GiB by default on data plane v2.17.0 and later (Helm chart 6.20.0 or Terraform module v6.9.0 and later), and 10 GiB on earlier versions.
failed status with an explanatory error.
Submit a query
POST /btql/async submits a query and returns its id, with a status of queued.
Example
Unlike
POST /btql, the async endpoint ignores fmt, lint_mode, version, and tz_offset, and query must be a string rather than a structured query object.
Response
JSON
Check status
GET /btql/async/:id returns the query’s progress. Poll it until the status is succeeded, failed, or canceled.
Example
id in the path.
Response
JSON
Fetch results
GET /btql/async/:id/result returns a page of results as rows, along with a cursor for the next page. Results are complete only after status is succeeded. Before then, this endpoint returns whatever rows are available so far.
Example
id in the path, and these URL query parameters:
Response
JSON
A page can contain fewer than
limit rows, so don’t treat a short page as the last one.
Cancel a query
POST /btql/async/:id/cancel cancels a queued or running query. Canceling a query that already finished discards its results. Only the user who submitted the query, or a user with update permission on the organization, can cancel it.
Example
id in the path.
Response
JSON
Next steps
- Learn the SQL syntax for querying logs, experiments, and datasets.
- Follow SQL best practices to keep queries fast and within limits.
- Run queries with the
bt sqlCLI command.