Responses and exports

A response is one submission of one stage by one participant: a document keyed by data type _id, each entry holding the value given, when and by whom. Participants submit through the app; staff enter and correct data on their behalf through the endpoints here, which is also how an integration pushes data collected elsewhere into a casebook.

Reading study data needs trial.readParticipantStudyData; writing it needs trial.writeParticipantStudyData; exporting it needs trial.exportData in addition (trial.read, trial.write and trial.admin imply these). Data types flagged as restricted or PII are left out unless you hold trial.readParticipantStudyDataRestricted or trial.readParticipantStudyDataPii. A locked database refuses every write.

Endpoints

Method Path Description
PUT /trials/<trialId>/participants/<participantId>/responses/<stageId> Submit or amend a participant's response to a stage.
DELETE /trials/<trialId>/participants/<participantId>/draftResponses/<stageId> Discard your draft for a stage.
GET /trials/<trialId>/participants/<participantId>/responses All of one participant's responses, with drafts, validations, signatures and queries.
GET /trials/<trialId>/participants/<participantId>/hardwareResponses?dataset= The participant's wearable and device data.
GET /trials/<trialId>/stages/<stageId>/responses Every response to one stage. ?type=csv exports them.
GET /trials/<trialId>/responses/<responseId> One response, with its validations, signatures and queries.
GET /trials/<trialId>/responses/<responseId>/history Every submission that built the response, oldest first, with what each value replaced.
DELETE /trials/<trialId>/responses/<responseId> Delete a response. Body: {"reason": "…"} (required). Needs trial.admin.
PUT /trials/<trialId>/responses/<responseId>/status Mark a response successful, unsuccessful or null. Needs trial.admin.
POST DELETE /trials/<trialId>/responses/<responseId>/validations Mark every field of a response as verified, or clear them all. Needs trial.admin.
POST DELETE /trials/<trialId>/responses/<responseId>/dataTypes/<dataTypeId>/validations Verify or unverify one field.
POST DELETE /trials/<trialId>/responses/<responseId>/allocations?participant= Move a response to a participant (for poll and unallocated responses), or detach it. Needs trial.admin.
GET /trials/<trialId>/responses?type=&dataset= Export the trial's data — see below.
GET /trials/<trialId>/signatures/casebooks Signature status of every participant's casebook.
GET /trials/<trialId>/participants/<participantId>/signatures Signatures on one participant's responses.

Signing responses (POST /trials/<trialId>/signatures) needs a fresh confirmation of identity and is done in the web app — see Authenticating requests.

Submitting a response

PUT /trials/<trialId>/participants/<participantId>/responses/<stageId>:

{
  "response": {
    "<dataTypeId>": {"value": 7},
    "<dataTypeId>": {"value": "Mild headache after dose"},
    "<dataTypeId>": {"value": ["Nausea", "Fatigue"]}
  },
  "updateNote": "Transcribed from paper CRF"
}
  • response is keyed by the _id of each data type in the stage. Only data types that are components of the stage are accepted; others are ignored.
  • Send only the fields you are setting. Fields you leave out keep their existing value — a response is amended field by field, and every change is kept in its history with who made it and when.
  • value takes the form of the data type: a string for text and paragraph; a number for integer, float, slider, rating and the measurements; an ISO datetime string with a Z (2026-09-22T00:00:00Z) for date and datetime; HH:MM or HH:MM:SS for time; a list of the chosen option labels for choice, whether or not it allows multiple (["Nausea", "Fatigue"]); an object keyed by statement key for a likert, each value a scale point's value or null for not applicable; a list of row objects keyed by column id for a table; {"bmi", "height", "weight"} for bmi; and {"fileName": "<stored name>", "name": "<original name>"} for file, image and video, after an upload with forType=participant. Values are validated against the data type's settings — ranges, lengths, allowed dates, valid options — and a value that does not fit is refused with 400. calculation fields are computed by Trialflare and cannot be set.
  • Each entry may also carry a createdAt saying when the answer was actually given, for data entered after the fact; it is kept as enteredAt. The time Trialflare recorded it is always its own clock.
  • updateNote is required when the trial's sign-off note setting is on.
  • For an occurrence of a recurring stage, use <stageId>::<n> as the stage ID, where n is the occurrence number starting at 0 — the same _id the participant's stages list shows.

Add ?draft=true to save a draft instead, which is yours alone until you submit it; DELETE …/draftResponses/<stageId> discards it.

The response returned holds the response's _id, stage, stageRecurrence, participant, createdAt, score where the stage scores, and the fields you sent as they were stored. Submitting a required field as blank is refused unless the stage allows partial submission, in which case the response is marked partialSubmission.

Reading responses

The three read endpoints — a participant's responses, a stage's responses, and one response — all return the same shape:

{
  "responses": [...],
  "responseValidations": [...],
  "signatures": [...],
  "queries": [...]
}

(the participant endpoint adds drafts and participant). Each response has _id, trial, stage, stageRecurrence, participant, participantId, createdAt, score, status, partialSubmission, and a response object keyed by data type _id:

"response": {
  "<dataTypeId>": {
    "value": 7,
    "createdAt": "2026-09-22T09:14:02.310000Z",
    "createdBy": "<user or participant _id>",
    "createdByType": "user",
    "updateNote": "Transcribed from paper CRF"
  }
}

The client (IP address and device) that submitted each field is included only for viewers with the personal-information permission.

?type=csv on the stage endpoint returns the stage's responses as a CSV string in {"csv": "…"} and needs the export permission.

Exporting

GET /trials/<trialId>/responses exports the whole trial. type picks the format; dataset picks what is exported and defaults to stage (the study data itself).

type Returns Notes
json (default) The data inline: {"participantCount", "stages": [...]}, each stage with its data types and responses. Viewing, not exporting — needs only the read permission.
raw The response documents inline, as stored, with a dataTypes map to interpret them. With dataset=hardware, a job whose result is a request URL for a zip.
csv {"csv": "…"} — one row per response, one column per data type. dataset=hardwareDaily, hardwareSleep, hardwareActivity or foodDiary export those instead.
excel {"request": "<url>"} — a workbook, one sheet per stage.
spss, stata, r, graphpad, pdf {"request": "<url>"} — a package for that tool, with variable and value labels. Need the advanced-export feature on your team.

Download URLs are temporary; see Downloading exports. Every export is recorded in the trial's event log with its format. Archived participants are left out. What is in the export is what you are permitted to see: restricted and PII fields are dropped for viewers without those permissions, and contact details are only included for holders of the personal-information permission.

The study record — a complete archive of the trial for the sponsor's file — is built from the trial rather than here.

Device and wearable data

Data from Garmin, Fitbit, Dexcom and similar sources is stored separately from stage responses. GET …/<participantId>/hardwareResponses?dataset=<name> lists one participant's, where the dataset is daily, sleep, activity, summary or egv (glucose); omit it for everything. The trial-wide CSV export takes dataset=hardwareDaily, hardwareSleep or hardwareActivity, and the raw export takes dataset=hardware for the lot. Which have data depends on the integrations the trial has enabled.

Validation and status

Source data verification is recorded per field: POST …/responses/<responseId>/dataTypes/<dataTypeId>/validations marks a field as verified against source by you now, and DELETE removes the mark. The whole response can be marked in one go with POST …/responses/<responseId>/validations. Verification marks appear as responseValidations alongside the responses they belong to. Both need trial.admin.

PUT …/responses/<responseId>/status with {"status": "successful"}, "unsuccessful" or null records an outcome on a response — for screening stages, say.

Signatures

Where the trial has casebook signing on, GET /trials/<trialId>/signatures/casebooks returns each participant's casebook status — how many responses are signed and whether the casebook is complete — and GET …/<participantId>/signatures lists the signatures on one participant's responses, each with its meaning, signer and time. Signing itself is done in the web app.