GET only
Every other method is 405 with Allow: GET. A published pipeline cannot have a write-shaped node, and the check is re-run at serve time — a pipeline that gained a write after publishing answers 503, not a write.
Published endpoints
Building an API over a dataset is usually a second project: a service, a deployment, auth, pagination,
on-call. Here it is one step after a release. A released pipeline is published under a path, a GET
runs it with bound parameters and returns JSON, and a key scoped to that path is the whole access story.
From data to an API in a day is the shipped half of the sentence; the dashboards you embed are
planned.
The mechanism
Only a released, side-effect-free pipeline can be published — a version a person locked, with no node that writes anywhere. The endpoint serves whatever version its pipeline's pointer names, so switching the served version is a lifecycle verb, not a redeploy.
A path is one to ten segments, literal or {variable}: /api/x/nyc/rain-share, /api/x/customers/{id}/orders. Path variables bind to the pipeline's declared parameters by name; the query string supplies the rest. Ambiguous patterns are refused at publish time, not resolved at call time.
An API key is bound to a path prefix. A caller holding it can reach that subtree of /api/x and nothing else — not the product's own API, not another workspace's endpoints. Give a partner one key per contract and the contract is enforced by the router.
A GET with the key in DP-API-Key. Validation reports every defect at once — an unknown parameter, a repeated one, a missing required one, a wrong type — because a client fixes a request once, not four times.
GET /api/x/nyc/rain-share?quarter=2024-Q3
DP-API-Key: dpk_<id>.<secret>
200 OK
{
"execution_id": "…",
"schema": [ { "name": "borough", "type": "STRING" },
{ "name": "rideshare_rain_lift", "type": "BIGDECIMAL", "precision": 18, "scale": 2 } ],
"rows": [ ["Manhattan", "1.18"], ["Brooklyn", "1.07"] ],
"row_count": 5, "total_rows": 5, "has_more": false,
"result_url": "…", "expires_at": "…", "ttl_seconds": 300
}
What the response is
The body is the same data_ready payload the product's own execution stream produces: a schema
with typed columns, the first page of rows, the total, and a cursor URL for the rest. Each call is a fresh
execution of the released version, run in-process as the endpoint's workspace, audited with the key, the
endpoint and the execution id. The response carries Cache-Control: no-store on purpose — a
result belongs to one execution, and a shared cache that held one would hand a second caller another
caller's rows.
When an endpoint's own timeout elapses, the execution is not killed and the client is not lied to: the
response is 202 with the execution id, a status URL and the result URL, and the rows are there
when the run finishes. A 504 would say the upstream failed; it did not.
What is returned is the pipeline's caller node — declared, not guessed from the graph's shape — so a pipeline that also writes to a table, or stages six intermediate results, still returns exactly one declared result.
What it is not
Every other method is 405 with Allow: GET. A published pipeline cannot have a write-shaped node, and the check is re-run at serve time — a pipeline that gained a write after publishing answers 503, not a write.
An unknown path and a disabled endpoint return the same 404 body, so the registry cannot be walked one URL at a time.
A session cookie is 401 here. This is a machine surface: keys, bound to paths, owned by a person who can revoke them.
429 with Retry-After when a caller exceeds its budget or the instance's execution slots — the same limits the product's own runs live under.
Why it matters
Teams that already have the data and already have the chart still spend a quarter getting the number into their own product, because “expose this dataset as an API” means a service, a schema, an auth story, a deployment pipeline and someone to wake up when it fails. That quarter is what a published endpoint removes. The agent authors the pipeline against your databases and iterates it until the numbers are right; you review and release; the endpoint exists. No service was written. Nothing was deployed. The on-call is the server you were already running.
It is also why the roadmap's dashboards are built the way they are — created by the same agent, fed by the same released pipelines and endpoints, embedded in your product rather than hosted in ours. The endpoint is the contract; the dashboard is a consumer of it, like any other.
Where you manage them
| endpoint | serves | key reach |
|---|---|---|
GET /api/x/demo/top-company-by-borough?anchor_date=2025-01-01 |
demo/top_company_by_borough · v1 | /demo/** |
from the demo workspace — released by a human, served as this version forever
Asked before
A released pipeline gets a URL under /api/x/…; a GET runs it with the query string bound to its declared parameters and returns the rows as JSON. Keys are bound to a path prefix, so a partner can be given one endpoint and nothing else. The serving contract is docs/rest-api.md §19.
For the API half, today: an agent authors the pipeline against your databases, runs it, fixes what fails, you review and release, and the endpoint exists — no deployment, no service to write, no gateway to configure. Dashboards your agent creates and you embed in your own product are a planned roadmap item; the roadmap page says so. Publishing is docs/rest-api.md §19.