POST /v1/analytics.query runs a read-only DuckDB SQL query over your Autumn data and streams the result back as newline-delimited JSON. Use it for reporting, reconciliation and one-off questions (“how many customers are on each plan?”) without exporting data or calling list endpoints page by page.
Each query sees only your own organization and the environment of the key you use: a sandbox key reads sandbox data, a live key reads live data. Data is roughly 15 minutes behind the API, so a customer you created a moment ago may not show up yet.
Available tables
Every table’s columns are listed in the schema reference.
Discovering the schema
List the tables and describe their columns with DuckDB’s own commands:information_schema.columns is empty, so use DESCRIBE instead.
Running a query
AnalyticsQueryLine objects. If you already hold a raw response body, for example from fetch, readAnalyticsQueryLines(body) from the same package does the same parsing. Breaking out of the loop early cancels the request.
The Python SDK returns the raw streaming httpx response in res.result. Iterate it with iter_lines() and close it when you’re done, which the with block does for you.
The response stream
The response hasContent-Type: application/x-ndjson: one JSON object per line, each with a type field.
How values are encoded in
row lines:
BIGINTandDECIMALvalues are strings, so large numbers and amounts keep their precision. Parse them withBigIntor a decimal library rather thanNumberwhen precision matters.- Lists are JSON arrays.
STRUCTcolumns come back as DuckDB’s text form. Selectto_json(col)to get JSON you can parse.
End lines, error lines and dropped connections
A successful stream always ends with anend line. If the result goes over the 1 GB output cap, the stream stops early and the end line has truncated: true and stopped_by: "byte_cap".
If the query fails after rows have started streaming, the last line is an error line instead, for example:
end nor an error line, the connection dropped and the result is incomplete. Treat it as a failure and retry rather than using the partial rows.
Errors before streaming
Errors that happen before the first line are regular JSON error responses withmessage, code, env and sometimes details. The SDKs raise them as API errors.
Limits
A query that runs past 30 seconds fails with
statement_timeout: a 408 response if no rows were sent yet, or a final error line if they were. Narrow the query with WHERE and LIMIT, or aggregate in SQL instead of fetching every row. If you need a higher limit, contact support@useautumn.com.
Compression
Responses are always compressed: with zstd when your client’sAccept-Encoding includes it, and with gzip otherwise. Both SDKs handle this for you. The TypeScript SDK asks for zstd on every server runtime (Node 20 and later, Bun and Deno) and decodes it itself where fetch doesn’t. In browsers it sends no Accept-Encoding of its own, so the browser picks the encoding and decodes it. The Python SDK installs zstandard, so httpx asks for and decodes zstd. With curl, pass --compressed and curl decodes whichever encoding it gets.