API & MCP
Dashboards API
The Dashboards API programmatically drives what the app does on the dashboard canvas: generating a dashboard from your data, saving edits safely under concurrent access, and browsing version history. Most people build dashboards in the app — reach for this API when you're automating (nightly regeneration, provisioning a dashboard per new dataset, an external editor).
Generate a dashboard#
There are three generate targets, matching the three kinds of dashboard:
| Endpoint | For |
|---|---|
POST /datasets/{datasetId}/dashboard/generate | a single dataset |
POST /projects/{projectId}/views/{viewId}/dashboard/generate | a saved view |
POST /projects/{projectID}/dashboards/generate | a whole project (multi-source) |
The dataset and view forms take no body — control them with ?use_ai=true (default) and ?force=false (regenerate an existing one). They return the full dashboard object with a spec, plus an ETag header (see concurrency below).
The project form takes a JSON body naming the sources:
curl -X POST "https://<your-gopie-host>/v1/api/projects/…/dashboards/generate" \
-H "Authorization: Bearer gp_pub_…" \
-H "Content-Type: application/json" \
-d '{"name": "Revenue overview", "intent": "track revenue and top products",
"dataset_ids": ["…", "…"], "use_ai": true}'At most 12 datasets and 6 reused views (18 sources total). Validation failures (name_required, no_sources, too_many_datasets) come back as 400.
Stream generation progress#
Each generate endpoint has a /generate/stream twin that reports progress as Server-Sent Events while the dashboard is built — the same five phases the app shows:
data: {"type":"progress","message":"Analyzing your data","data":{"phase":"analyzing"}}
data: {"type":"progress","message":"Selecting key metrics","data":{"phase":"metrics"}}
data: {"type":"progress","message":"Validating queries","data":{"phase":"validating"}}
data: {"type":"progress","message":"Designing the layout","data":{"phase":"layout"}}
data: {"type":"progress","message":"Finalizing your dashboard","data":{"phase":"finalizing"}}
data: {"type":"complete","message":"Dashboard generated","data":{"id":"…","spec":{…}}}Phases are analyzing → metrics → validating → layout → finalizing, a heartbeat fires during long steps, and a terminal complete carries the finished dashboard. If the AI service is unavailable or use_ai=false, GoPie builds a deterministic dashboard in-process and the stream still completes — it never stalls.
Save edits safely#
Dashboards use optimistic concurrency so two editors don't clobber each other. Every GET and PUT returns an ETag header — a fingerprint of the dashboard's current state:
ETag: "1720107000123456789"To update, send that value back in If-Match:
curl -X PUT "https://<your-gopie-host>/v1/api/dashboards/…" \
-H "Authorization: Bearer gp_pub_…" \
-H 'If-Match: "1720107000123456789"' \
-H "Content-Type: application/json" \
-d '{"spec": {…}, "display_name": "Q3 revenue"}'If someone else changed the dashboard since you read it, the tags won't match and you get a 412 — reload and retry:
{ "code": 412, "error": "dashboard_modified", "message": "The dashboard was modified by another session. Please reload." }If-Match is optional; omit it to write unconditionally (at the cost of the safety check).
List, read & delete#
| Method + path | Effect |
|---|---|
GET /dashboards | list dashboards (query, limit, page) |
GET /dashboards/{dashboardId} | one dashboard + can_edit + ETag |
PUT /dashboards/{dashboardId} | update spec / display_name (honours If-Match) |
DELETE /dashboards/{dashboardId} | delete it (204) |
GET /projects/{projectId}/dashboards | dashboards in a project |
Refine with a prompt — POST /dashboards/{dashboardId}/refine#
Apply a natural-language edit ("add a discount KPI", "make the revenue chart a line") to a dashboard or a single tile — the API behind dashboard chat:
{ "user_prompt": "add an average-discount KPI", "scope": "dashboard" }For a tile-scoped edit, set "scope": "tile" and a "tile_path" like rows.0.items.2. The refined dashboard comes back in the response.
Browse version history#
Every generate, edit and refine records a version:
| Method + path | Effect |
|---|---|
GET /dashboards/{dashboardId}/versions | list versions (spec omitted, for a light payload) |
GET /dashboards/{dashboardId}/versions/{versionId} | one version, with its full spec |
POST /dashboards/{dashboardId}/versions/{versionId}/restore | restore it (honours If-Match) |
PATCH /dashboards/{dashboardId}/versions/{versionId} | name it ({"message": "…"}) or clear the name |
POST /dashboards/{dashboardId}/versions/{versionId}/pin · /unpin | pin against cleanup |
Plan a project dashboard (wizard)#
The app's project dashboard wizard is three endpoints you can call directly to build a guided flow: POST /projects/{projectID}/dashboards/recommend-intent (suggest what the dashboard should cover), recommend-datasets (rank which datasets to include), and plan-views (propose the joins as validated view definitions). Each returns structured suggestions you can present, edit, then feed into the project generate call above. When the AI service is down, recommend-datasets falls back to ranking by row count so the flow still works.