dDatahopdocs
Reference

REST API

Authentication, errors and the main endpoints for scripts, backends and agents that don't use MCP.

Everything you do in the app, you can do over the REST API. It's what the MCP tools use too. For most agent work, MCP or the CLI is easier.

Basics

https://app.datahop.dev/api/projects/:projectId/…
  • Project id: it's in the app's URL (/p/1/…), or ask GET /api/me.
  • Auth: Authorization: Bearer dh_sk_…, with an API key for that project.
  • JSON in and out. PATCH changes only the fields you send.
  • Times are ISO 8601 in UTC. Chart labels are in the project timezone.
  • Endpoints that take a person accept a person id or a distinct id.
  • Names in paths must be URL-encoded, for example /events/%24pageview.

Errors

Every error looks like this:

{ "error": "invalid_query", "message": "Math \"sum\" needs mathProperty", "hint": "Set mathProperty to a numeric event property, e.g. \"amount\"" }

Branch on error. Show or log message and hint: hints say how to fix the call.

StatuserrorMeaning
400invalid_query, invalid_request, …Something in the request is wrong. Check the hint.
401unauthorizedMissing or invalid key.
403forbiddenA read-only key tried to write, the key belongs to another project, or only signed-in people can do this.
403module_disabledThat product is switched off in Settings → Products.
404not_foundIt doesn't exist.
409key_taken, in_use, invalid_state, experiment_runningA conflict: a flag key already exists, something is still in use, an experiment is in the wrong state, or you're changing a running experiment's variants.

Run any analysis

POST /query takes any query object and returns the result with a summary.

curl -s https://app.datahop.dev/api/projects/1/query \
  -H "Authorization: Bearer $DATAHOP_KEY" -H 'content-type: application/json' \
  -d '{ "kind": "funnel", "steps": [{ "event": "signed_up" }, { "event": "plan_upgraded" }], "windowDays": 14 }'

Results can be up to a minute old. Add ?refresh=1 to get fresh numbers.

Endpoints

Paths are relative to /api/projects/:projectId. W needs a read & write key.

AreaEndpoints
SchemaGET /events · PATCH /events/:name W (description) · GET /properties?type=event|person|group · PATCH /properties/:type/:key W · GET /property-values?key=
InsightsGET /insights · GET /insights/:id · POST /insights W · PATCH /insights/:id W · DELETE /insights/:id W
DashboardsGET /dashboards · GET /dashboards/:id · POST /dashboards W · PATCH /dashboards/:id W · DELETE /dashboards/:id W · POST /dashboards/:id/tiles W · PATCH /dashboards/:id/tiles/:tileId W · DELETE /dashboards/:id/tiles/:tileId W · PUT /dashboards/:id/share W
PersonsGET /persons?search=&cohortId= · GET /persons/:id · PATCH /persons/:id W ({ set, unset }) · DELETE /persons/:id W
CohortsGET /cohorts · GET /cohorts/:id · POST /cohorts W · PATCH /cohorts/:id W · DELETE /cohorts/:id W · GET /cohorts/:id/persons · POST /cohorts/:id/calculate · POST /cohorts/:id/members W · DELETE /cohorts/:id/members W
GroupsGET /group-types · PATCH /group-types/:index W (display names) · GET /groups?groupTypeIndex=&search= · GET /groups/:index/:key
Feature flagsGET /flags · GET /flags/:id · POST /flags W · PATCH /flags/:id W · DELETE /flags/:id W · POST /flags/evaluate
ExperimentsGET /experiments · GET /experiments/:id · POST /experiments W · PATCH /experiments/:id W · POST /experiments/:id/launch W · POST /experiments/:id/stop W · POST /experiments/:id/conclude W · DELETE /experiments/:id W · GET /experiments/:id/results · POST /assist/experiment (draft from a description)
FeedbackGET /feedback?status=&cohortId=&search= · GET /feedback/stats · PATCH /feedback/:id W
ContextGET /annotations · POST /annotations W · DELETE /annotations/:id W · GET /activity
ProjectGET /api/projects/:projectId · PATCH /api/projects/:projectId W (name, timezone) · GET /modules · PATCH /modules W (products on/off)

Lists of persons and groups return { total, results } and page with limit (up to 200) and offset.

Creating and revoking API keys, rotating the project token and deleting the project are only possible for signed-in people in the app.

Examples

# create a cohort of power users
curl -s https://app.datahop.dev/api/projects/1/cohorts \
  -H "Authorization: Bearer $DATAHOP_KEY" -H 'content-type: application/json' \
  -d '{ "name": "Power users", "definition": { "match": "all", "criteria": [
        { "type": "behavior", "event": "project_opened", "withinDays": 14, "minCount": 20 } ] } }'

# widen a flag to 30% of everyone
curl -s -X PATCH https://app.datahop.dev/api/projects/1/flags/4 \
  -H "Authorization: Bearer $DATAHOP_KEY" -H 'content-type: application/json' \
  -d '{ "active": true, "filters": { "conditions": [{ "properties": [], "rolloutPercentage": 30 }] } }'

# conclude an experiment and roll out the winner
curl -s https://app.datahop.dev/api/projects/1/experiments/4/conclude \
  -H "Authorization: Bearer $DATAHOP_KEY" -H 'content-type: application/json' \
  -d '{ "winner": "test", "reason": "+26.9% upgrades, driven by new users.", "rollOut": true }'

The fields for flags, experiments and cohorts match what you see in the app. Flag conditions use property filters, and cohort rules use cohort definitions.

On this page