Studies API
Create Studies, run cohesive multi-question blocks with Audiences, inspect results, and export artifacts through the Minds v1 API.
A Study is the research workspace. It contains one or more Audiences, questions, evidence, results, analysis, and exports.
Base URL: https://api.getminds.ai/v1
Study list and detail responses include isPublic, isLinkSharingEnabled, and publicShareId. A retained publicShareId alone does not establish public access: the share route requires isPublic: true or isLinkSharingEnabled: true. Recheck visibility before handing a link to a recipient.
GET /studies/{studyId}/runs returns newest-first pages: limit defaults to 20 and is capped at 100. Continue with before set to pagination.nextCursor while pagination.hasMore is true. clientRequestId filters by the original request UUID; preserve that filter on later pages. Invalid, foreign, or mismatched cursors return 400.
Public shared-Study views exclude guest conversations and retired subthreads, including direct answer reads. Shared transcript metadata contains presentation and research fields; model-connection settings, internal guided context, generation diagnostics, and language-review drafts are omitted. Answers and citations remain available for public messages. Authenticated workspace readers still require Study access.
Shared transcript endpoints (/api/app/studies/shared/{shareId} and /api/studies/shared/{shareId}) page messages with limit (default 100, maximum 500) and after. Follow data.pagination.nextCursor while data.pagination.hasMore is true, even when a page contains no public messages. Each page checks current sharing permissions; invalid or foreign cursors return 400. Transcripts contain aggregate results; load respondent answers separately. The shared page follows all pages automatically.
Create a Study
curl -X POST "https://api.getminds.ai/v1/studies" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Launch positioning",
"audienceIds": ["audience-id-1", "audience-id-2"]
}'
Canonical Study responses use studyMode: "study" and an audiences collection. Inline audienceConfigs can create and attach Audiences atomically; if any inline Audience fails, the entire composite creation is rolled back.
Run questions as a cohesive block
For a broader objective or more than one question, use the guided lifecycle. Do not submit a questionnaire one question at a time.
POST /studies/{studyId}/research-plans/previewcreates or revises a versioned plan containing the cohesive question modules.- Review the exact plan and answer any confirmation questions.
POST /studies/{studyId}/research-runsconfirms one precise revision and queues all questions together.GET /studies/{studyId}/research-runs/{runId}returns durable progress, response contracts, artifacts, calculations, and next actions.
The planner may use multiple named modules or sections when that improves the research design. Each module should contain related questions with a clear purpose; the executor preserves the reviewed order and shared context.
Use POST /studies/{studyId}/ask only for a genuinely standalone question. Use POST /studies/{studyId}/runs for a durable direct run that needs polling, replay, cancellation, or knowledge-only source policy.
A research run can finish collecting with status: "partial" when a question or respondent answer is missing. Stop polling this terminal state and explain the gap; do not describe it as complete. progress.pct measures settled questions, not respondent coverage. New question outputs retain outputData.responseCoverage with expected, received, and missing Audience/Mind memberships. progress.partial counts questions with recorded incomplete coverage. Missing coverage on older artifacts is unknown, not proof that everyone answered. Keep valid raw answers and their outcomes unchanged; review missing work before starting a separate retry.
Observe pending plan preparation
Send a stable Idempotency-Key (an opaque nonblank string of at most 200 characters) when preparing a plan. POST /studies/{studyId}/research-plans/preview can return HTTP 202 with an owned preparation receipt:
{
"data": {
"status": "pending",
"accepted": true,
"operationId": "87b41085-4a73-4b04-88af-d9a2370ecdee",
"requestId": "plan-reusable-cup-01"
}
}
Repeat the same POST with the exact original JSON body and the same Idempotency-Key. Keep the returned requestId in x-minds-study-plan-request-id; the returned operationId can also be sent in x-minds-study-plan-operation-id. The operation ID is an owned observation hint, not permission to access another operation. stage may be included as optional progress. Reconnecting or aborting observation does not cancel accepted preparation. Do not use a fresh key merely to check progress.
accepted: true confirms durable preparation, not a completed plan or a started research run. Continue observing until HTTP 200 returns the original completed preview DTO. Review that exact saved revision before confirming a research run. Existing authorization, malformed-input and revision-control 4xx responses remain authoritative.
loadLatest and completed-plan reads return 200. Fixed instruments in questions and deterministic edits keep their existing no-planner meaning; they can still return 202 while required downstream source or preparation verification finishes.
Questionnaire runs: order, skip logic, and consistency
Each Mind answers as one respondent
A confirmed run (POST /studies/{studyId}/research-runs) is answered the way one respondent answers a questionnaire. Items run in the reviewed order. Every Mind answers an item in parallel with the other Minds, and each Mind sees its own earlier answers in this run: never another Mind's answers and never an aggregate. A later item can therefore build on an earlier one, and a Mind stays consistent with what it already said about itself. No request field turns this off.
Items in a confirmed run are not independent measurements. Order effects can arise as they do in a fielded survey, so question order is part of the design. When the design calls for it, control order effects by rotating item order across separate runs; a separate run does not see the answers of another run. A direct run (POST /studies/{studyId}/runs) is different: its historyMode defaults to none, which treats every question as an independent measurement.
Skip logic with askIf
Give a question askIf to ask it only of Minds whose own answer to an earlier choice question matched. Use this instead of respondent-visible wording such as "if not, answer N/A". Set it on a fixed-instrument item in questions[] of POST /studies/{studyId}/research-plans/preview, or on an item in edits.questions[] when revising a saved draft. Edits are authoritative: an edited item sent without askIf has no condition. The saved plan snapshot keeps the condition on its question.
{
"questions": [
{
"id": "owns_car",
"text": "Do you own a car?",
"response": { "type": "categorical", "categoricalOptions": ["Yes", "No"] }
},
{
"id": "car_brand",
"text": "Which brand is your main car?",
"response": { "type": "qualitative" },
"askIf": { "questionId": "owns_car", "answerIn": ["Yes"] }
}
]
}
| Field | Meaning |
|---|---|
questionId | ID of an earlier question in the same plan (up to 80 characters, normalized to the saved ID slug). It must be a categorical or multiselect question. |
answerIn | Ask when the Mind's answer includes any of these options. |
answerNotIn | Ask when the Mind's answer includes none of these options. |
Give exactly one of answerIn or answerNotIn, with 1 to 100 of the earlier question's option labels exactly as the plan stores them. Labels are matched as written, not interpreted, so a condition means the same thing in every language. An empty multiselect selection is an answer: it matches no answerIn, so answerNotIn items are asked. A Mind with no answer to the earlier question (it was not asked it, or its answer failed) is not asked. If the earlier question recorded no answers at all, every Mind is asked and the item's routing.gateUnavailable is true.
A condition that cannot run is rejected with 400, naming the question: both or neither of answerIn/answerNotIn, an unknown questionId, a question that is not earlier, a question that is not categorical or multiselect, or an option the earlier question does not offer. A fixed instrument returns Fixed instrument is not executable as given: …; an edit returns the issues directly; confirming a run revalidates the plan and returns Invalid question conditions: ….
Items and answers not asked
Run status (GET /studies/{studyId}/research-runs/{runId}) reports routing on each routed item's response artifact: routing carries questionId, gateQuestionId, the answerIn or answerNotIn condition, askedCount, notAskedCount and notAskedMindIds. An item that no Mind was asked settles as an artifact with kind: "not_asked" and no outputData. It is finished, not failed, and it does not make the run partial.
Minds that were not asked are outside the item's results. The item's answers, response counts, percentages, distributions and responseCoverage.expected cover the asked Minds only, so a share on a routed item is a share of those asked. Not asked is different from did not answer: a Mind listed in notAskedMindIds has no answer to read, while a missing asked answer shows up in responseCoverage. Individual-answer reads (GET /studies/{studyId}/messages/{messageId}/answers) return only the asked Minds' answers; a not_asked item has no answer data and returns 404.
Answer consistency flags
After a confirmed run of two or more items finishes, each Mind's answers are checked against its own other answers in the run. The check never changes an answer; it only records flags beside the answers for review. It runs after the run's summary is written, so it never delays the summary and can arrive shortly after status becomes completed. It does not run for a cancelled or plan-limited run, and a failed or cut-short check never fails the run.
The run status then carries answerConsistency:
| Field | Meaning |
|---|---|
status | checked; incomplete when the time budget or a cancellation stopped the check before every Mind was checked; failed when the check failed or no flag could be saved |
checkedMinds | Minds whose answers were checked |
flaggedMinds | Minds with at least one flag |
flagCount | Contradicting answer pairs found |
uncheckedMinds | Minds whose check could not run; their answers are unflagged, not cleared |
unsavedItems | Present only when some flags could not be saved: the run item indexes whose flags are missing; other items keep theirs |
A flagged response artifact carries answerConsistency.flags, one entry per contradiction involving that item: mindId, withItem (the run item index of the other answer) and reason. Each pair is flagged on both items. Only Minds that answered at least two items are checked. Treat a flag as a prompt to review both answers, not as proof that either is wrong.
Core endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /studies | List Studies |
POST | /studies | Create a Study from Audiences |
GET | /studies/{studyId} | Read Study composition and history |
DELETE | /studies/{studyId} | Delete a confirmed Study |
POST | /studies/{studyId}/ask | Ask one standalone question |
POST | /studies/{studyId}/runs | Start a durable direct run |
GET | /studies/{studyId}/analytics | Compute categorical, scale, multiselect, and qualitative analytics |
GET | /studies/{studyId}/summary | Read the persisted semantic summary |
POST | /studies/{studyId}/summary | Generate or refresh the semantic summary |
PUT | /studies/{studyId}/sharing | Change public link sharing after explicit approval |
POST | /studies/{studyId}/duplicate | Copy the Study with all of its results over the same Audiences |
To have your team's own model write the Mind answers, pass modelConnection: { "id", "revision" } on POST /studies/{studyId}/runs or POST /studies/{studyId}/research-runs (see your own model). The connection needs text and structured output. Supporting analysis still uses Minds models, and each answer still counts toward your plan's Study responses. POST /studies/{studyId}/ask does not accept a connection.
For POST /studies/{studyId}/summary, send a JSON object up to 4 KiB with only force (boolean; default false) and length (short, standard, or detailed; default standard). Invalid JSON, types, options, or extra fields return 400; larger bodies return 413. Summary reads and refreshes require Study access and return Cache-Control: private, no-store. A refresh reuses the saved summary only when its length, covered message count and final covered message still match.
Summary reads return a monotonic revision and an isGenerating flag alongside summary; generation responses also include revision. A generation superseded by a newer generation or deletion returns 409 and cannot overwrite the newer state. Reload the summary before retrying.
Duplicate a Study
POST /studies/{studyId}/duplicate creates a private copy of a Study you can open, over the same Audiences and Minds. The copy keeps every question, answer, chart and heatmap, the semantic summary and finished runs; a schedule is copied paused. Sharing, exports and shared-link guest threads are not copied. Audiences are referenced, not copied: duplicate an Audience separately to copy its Minds.
The optional body takes name (default <name> (copy)) and idempotencyKey; the Idempotency-Key header wins. A repeated key returns the same copy with 200; a new copy returns 201 with the StudyCreated shape. Attached Audiences and your plan are checked as for POST /studies. A Study with a live run returns 409 with STUDY_RUN_IN_PROGRESS; retry when it has finished, or cancel the run first.
Exports
Start an artifact with POST /studies/{studyId}/export, poll /export-status, then download from /export-download. Supported outputs include the full report, executive summary, raw data, and presentation formats exposed by the export endpoint.
Compatibility
The former /panels routes remain callable during the migration window. They return Deprecation: true and a Link header naming the canonical /studies successor. Deprecated routes retain legacy wire fields such as groupIds, groups, and flowMode: "panel"; new integrations should use audienceIds, audiences, and studyMode: "study".
See the exhaustive v1 endpoint reference, the agent integration guide, and the live OpenAPI document.
n8n workflows
The n8n Study workflow guide shows how to pass the ID returned by Create into Preview Research Plan, then retrieve the same Study later. Version 0.1.0 prepares a draft; approving and starting its research is a separate step in Minds.


