Menu
On this page

API & MCP

Downloads API

The downloads endpoints export a query result to a file (CSV, JSON, or Parquet) and give you a link to fetch it. Unlike the 1,000-row cap on live queries, a download can be any size — it streams the full result straight to object storage. This is the API behind the app's Downloads & exports.

Create a download — POST /downloads

The one surprise: create is a streamed connection, not a fire-and-forget id. You POST the request and hold the connection open; the server reports progress as Server-Sent Events and delivers the finished download link in the final event.

curl -N -X POST "https://<your-gopie-host>/v1/api/downloads" \
  -H "Authorization: Bearer gp_pub_…" \
  -H "Content-Type: application/json" \
  -d '{
    "dataset_id": "gp_DzuutVJef9rSG",
    "sql": "SELECT * FROM gp_DzuutVJef9rSG WHERE region = '\''West'\''",
    "format": "csv"
  }'
Body fieldRequiredMeaning
dataset_idyesthe dataset UUID or its gp_… table name (either works)
sqlyesthe read-only SQL to export
formatyescsv, json, or parquet
snapshot_versionnoexport a past version

The stream is a sequence of data: events. Progress arrives as status_update, a heartbeat fires every 15 seconds so the connection stays alive, and the terminal complete event carries the presigned download URL in its message:

data: {"event":"status_update","message":"Processing query..."}

data: {"event":"status_update","message":"Executing data export to S3..."}

data: {"event":"complete","message":"https://<storage>/…/export.csv?signature=…"}

Fetch that URL to get the file. It expires 24 hours after creation. If a failure occurs mid-export it arrives as an error event rather than an HTTP status code — the connection had already upgraded to a stream.

Note

Identical requests are deduplicated. If you ask for the same (dataset, SQL, format, version) you exported recently and the data hasn't changed, the complete event returns the existing link immediately instead of re-running the query.

List your downloads — GET /downloads

Returns your recent downloads (a bare JSON array, newest paged by limit/offset):

[
  {
    "id": "550e8400-…",
    "sql": "SELECT * FROM gp_DzuutVJef9rSG WHERE region = 'West'",
    "dataset_id": "…", "status": "completed", "format": "csv",
    "pre_signed_url": "https://<storage>/…/export.csv?signature=…",
    "expires_at": "2026-07-05T…", "completed_at": "2026-07-04T…"
  }
]

status is one of pending, processing, completed, or failed. The pre_signed_url and expires_at are populated once a download completes.

Get or delete one — GET / DELETE /downloads/{id}

GET /downloads/{id} returns a single download record by its UUID — handy for re-fetching a still-valid link. DELETE /downloads/{id} removes the record and returns 204 No Content.