Menu
On this page

API & MCP

API overview & authentication

GoPie exposes a read-only HTTP API for querying your data, plus an MCP server for connecting AI clients. Both live on the same surface, authenticated by an API key sent as a bearer token. This page is the shared foundation — read it once, then jump to the endpoint you need.

Everything here is already reachable from inside the app: every dataset is an instant REST API, and you create keys under applications. The reference pages exist for when you're calling GoPie from your own code, a scheduled job, or another service.

The base URL

The public API and MCP are served on a dedicated port — 8002 — separate from the app itself. In a hosted deployment that port sits behind your GoPie host, so every path in these docs is relative to:

https://<your-gopie-host>/v1/api

The one exception is MCP, which is served at /mcp (no /v1/api prefix). On a local self-hosted stack the surface is http://localhost:8002. The API is read-only — there are no write endpoints for data on this port; ingestion happens in the app or through MCP tools.

Authenticate every request

Send your key as a bearer token:

curl -H "Authorization: Bearer gp_pub_your_key_here" \
  https://<your-gopie-host>/v1/api/config

There is no session, no cookie, no OAuth handshake — just the header, on every request. A missing or malformed header is rejected immediately:

{ "code": 401, "error": "Authorization header is missing", "message": "Unauthorized" }

Two kinds of key

GoPie has two distinct key types, and using the wrong one is the most common first mistake:

Application keyOrganisation-wide key
Prefixgp_pub_gp_mcp_
Created inSettings → Applications (guide)no UI yet — see MCP overview
Reachesonly the projects & datasets its application grantseverything in the organisation
Use it forthe REST data APIthe REST data API and MCP
MCP endpointrejected (403)accepted

Both act with organisation-owner privileges for role checks — the only thing that narrows an application key is its grants. So an application key scoped to one dataset can read exactly that dataset; an organisation-wide key can read every dataset in the org. Treat organisation-wide keys with extra care.

Important

Application keys and the datasets/projects you share with a teammate are unrelated systems. Granting a person a dataset does nothing for any API key, and an application's grants have nothing to do with member access — they're scoped independently.

The identifiers you'll juggle

Four identifiers show up across the endpoints. Getting them straight saves a lot of 404s:

IdentifierLooks likeWhat it is
Project id550e8400-… (UUID)a project
Dataset id550e8400-… (UUID)a dataset, for metadata & sharing endpoints
Table namegp_Dh790Asdf17kdthe dataset's physical name — what you query with
AliasOrdersthe dataset's human-friendly display name (not a path param)

The load-bearing subtlety: query endpoints take the gp_… table name, metadata endpoints take the UUID. They're two keys for the same dataset. The alias is only for display and search.

Discover what you can reach

There is no "list projects" endpoint on this port. Instead, list datasets — the response embeds each dataset's project, so one call gives you projects, datasets, and the table names you query with:

curl -H "Authorization: Bearer gp_pub_…" \
  "https://<your-gopie-host>/v1/api/datasets?limit=20"
{
  "results": [
    { "id": "…", "name": "gp_DzuutVJef9rSG", "alias": "Orders",
      "row_count": 1200, "project_id": "…", "project_name": "Sales Analytics" }
  ],
  "offset": 0, "limit": 20, "total": 3
}

Take name (the gp_… value) and you're ready to query. Full listing details are on the Datasets API page.

The error envelope

Errors return a small JSON object. The numeric code mirrors the HTTP status; message is a human summary and error carries the specific reason:

{ "code": 403, "error": "This API key is not scoped to the requested dataset", "message": "Forbidden" }

What you'll see:

StatusWhen
400malformed body, an invalid filter operator, a non-read-only or multi-statement SQL query
401missing, malformed, expired, or disabled key
403an application key reaching a dataset or project it wasn't granted
404no dataset with that table name or id in your organisation
500an unexpected server-side error
Note

The error field is usually a string, but validation failures on POST /sql return an array of {field, tag, value} objects instead. Read code to branch, then inspect error for detail.

Rate limits

Rate limiting is off by default. When a deployment enables it (GOPIE_RATELIMIT_ENABLED=true), requests are counted per API key — the default budget is 1,000 requests per minute. Over the limit, you get:

{ "code": 429, "error": "rate_limited", "message": "too many requests; slow down and retry" }

with a Retry-After: 60 header. There are no X-RateLimit-* headers — honour Retry-After and back off.

Where to next

  • Querying data/sql, the /tables REST facade, /nl2sql, schemas, summaries and config. Start here.
  • Datasets API — list and inspect datasets, edit column descriptions, share, reindex.
  • Downloads API — export query results to a file over a streamed connection.
  • Chat API — drive the SQL agent and consume its streamed answer.
  • Dashboards API — generate and manage dashboards programmatically.
  • MCP — connect Claude, Cursor and other AI clients to your data.