REST · v1

Studies

The API is the same one the product uses. There is no second public API that drifts from an internal one, because there is no internal one — which is why an endpoint here cannot be behind what the dashboard does.

Endpoints

GET    /api/v1/studies                    ?project=&status=&cursor=
POST   /api/v1/studies
GET    /api/v1/studies/:id
PATCH  /api/v1/studies/:id                status, name — never definition
POST   /api/v1/studies/:id/publish
POST   /api/v1/studies/:id/duplicate
DELETE /api/v1/studies/:id                requires an explicit confirmation flag
GET    /api/v1/studies/:id/responses      ?cursor=&since=
GET    /api/v1/studies/:id/export.csv
GET    /api/v1/studies/:id/analysis       the analyse() output, per block

Pagination is cursor-based, everywhere

Offset pagination over a table that participants are writing to skips and repeats rows. For a research tool that means an export which silently omits responses, which is the one failure this product exists to avoid.

Scopes

A key’s effective permission is the intersection of its scopes and the role of whoever created it. A researcher’s key cannot delete a study, because the researcher cannot.

studies:read   studies:write   responses:read   responses:write
library:read   library:write   insights:read    insights:write
org:read

Errors

An expired token returns 401 token_expired, distinguishable from token_revoked and insufficient_scope — three different fixes deserve three different codes.