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"
}
responseis keyed by the_idof 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.
valuetakes the form of the data type: a string fortextandparagraph; a number forinteger,float,slider,ratingand the measurements; an ISO datetime string with aZ(2026-09-22T00:00:00Z) fordateanddatetime;HH:MMorHH:MM:SSfortime; a list of the chosen option labels forchoice, whether or not it allows multiple (["Nausea", "Fatigue"]); an object keyed by statementkeyfor alikert, each value a scale point'svalueornullfor not applicable; a list of row objects keyed by columnidfor atable;{"bmi", "height", "weight"}forbmi; and{"fileName": "<stored name>", "name": "<original name>"}forfile,imageandvideo, after an upload withforType=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 with400.calculationfields are computed by Trialflare and cannot be set.- Each entry may also carry a
createdAtsaying when the answer was actually given, for data entered after the fact; it is kept asenteredAt. The time Trialflare recorded it is always its own clock. updateNoteis 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, wherenis the occurrence number starting at 0 — the same_idthe 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.