MeasureHub API
Run MeasureHub studies inside your own platform: pull rendering-ready instrument content, submit participant responses, and read scored results. Everything the API returns respects the same licence and disclosure rules as the web app.
Create a personal key in Account settings and send it as a bearer token. Keys are hashed at rest, can be revoked at any time, and carry a read and/or write scope.
curl https://YOUR-DOMAIN/api/public/v1/studies \ -H "Authorization: Bearer mh_live_xxx"
Rate limits: 120 requests per minute and 10,000 per day per key. Exceeding a limit returns 429 rate_limited.
/api/public/v1/studiesList your studies/api/public/v1/studiesCreate a study under an approved licence/api/public/v1/studies/{id}Retrieve one study/api/public/v1/studies/{id}Update a study or publish it/api/public/v1/studies/{id}/contentModules, questions, instrument items and translations, ready to render/api/public/v1/studies/{id}/sessionsList participant sessions/api/public/v1/studies/{id}/sessionsStart a session, returns a session token/api/public/v1/studies/{id}/resultsresponses | scores | sessions | paradata, as JSON or CSV/api/public/v1/sessions/{id}/responsesSubmit responses/api/public/v1/sessions/{id}/finishFinish the session and score it/api/public/v1/instrumentsBrowse the public instrument catalogue/api/public/v1/licensesList your instrument licences/api/public/v1/licensesRequest a licence# 1. Fetch rendering-ready content
GET /api/public/v1/studies/{studyId}/content
# 2. Start a session for a participant
POST /api/public/v1/studies/{studyId}/sessions
-> { "sessionId": "...", "token": "..." }
# 3. Submit answers as the participant progresses
POST /api/public/v1/sessions/{sessionId}/responses
{ "token": "...", "responses": [{ "variableCode": "PHQ1", "valueNum": 2 }] }
# 4. Finish and score
POST /api/public/v1/sessions/{sessionId}/finish
{ "token": "..." }
# 5. Pull data any time
GET /api/public/v1/studies/{studyId}/results?dataset=scores&format=csvRegister endpoints in Account settings. Outgoing events are posted as JSON to your URL; incoming endpoints give you a private URL you can push data to.
Payload
POST https://your-app.example/hooks/measurehub
x-measurehub-event: session.completed
x-measurehub-delivery: 6b1f...
x-measurehub-signature: t=1767225600,v1=9f86d0...
{
"id": "evt_...",
"type": "session.completed",
"created_at": "2026-08-05T10:00:00.000Z",
"api_version": "v1",
"data": { "sessionId": "...", "studyId": "...", "scores": [] }
}Verifying the signature
import crypto from "node:crypto";
const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
const expected = crypto
.createHmac("sha256", process.env.MEASUREHUB_WEBHOOK_SECRET)
.update(`${t}.${rawBody}`)
.digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));The signed string is {timestamp}.{raw body}. Reject anything older than five minutes. Deliveries are retried up to six times (1m, 5m, 30m, 2h, 6h) and an endpoint pauses automatically after 20 consecutive failures. Respond with any 2xx within 10 seconds.
Events
session.started A participant opened a study and a session was created.
session.completed A participant finished a study; scores are included.
session.abandoned A session was started but left incomplete past the timeout.
study.published A study moved to live.
study.closed A study stopped accepting participants.
study.target_reached Completed sessions reached the target sample size.
license.requested A researcher requested a licence for an instrument.
license.approved A licence request was approved.
license.rejected A licence request was rejected.
license.expiring A licence expires within 30 days.
license.expired A licence reached its expiry date.
instrument.submitted An instrument was submitted for platform review.
instrument.approved An instrument was approved and can be used in studies.
instrument.revision_requested A reviewer asked for changes.
instrument.translation_approved A language version was approved.
Pushing data in
curl https://YOUR-DOMAIN/api/public/v1/webhooks/in/{slug} \
-H "content-type: application/json" \
-H "x-measurehub-signature: t=<unix>,v1=<hmac>" \
-d '{"action":"session.create","data":{"studyId":"..."}}'session.create Start a participant session for one of your live studies.
session.responses Submit answers for an existing session.
session.finish Complete a session and run automatic scoring.
panel.invite_status Update the status of a panel invitation you sent.
course.enrollment_upsert Add or update a student enrolment in one of your courses.
Errors return { "error": { "code", "message" } } with codes such as unauthorized, insufficient_scope, not_found, validation_failed and rate_limited.
Item wording and scoring artefacts of protected instruments are only served for studies covered by an approved, unexpired licence.
