Panels API
Create and manage AI panels for surveying groups of minds with structured response aggregation. Ask questions, attach files, and export panel results.
Panels allow you to survey groups of AI minds with questions and receive aggregated, structured responses. This is useful for market research simulations, persona-based feedback gathering, and multi-perspective analysis.
Base URL: https://getminds.ai/api/v1 or https://api.getminds.ai/v1
Concepts
| Concept | Description |
|---|---|
| Panel | A container for surveying multiple mind groups with questions |
| Mind Group | A collection of minds that respond together (e.g., "Gen Z Users", "Senior Developers") |
| Question | A prompt sent to all minds in the panel's groups |
| Aggregated Response | AI-classified and grouped responses with scale or categorical values |
Guided Research Study Lifecycle
Use the guided lifecycle for multiple questions, a broader brief, an explicit method, a structured report, or analysis of a website, image, ad, video, or document. A single direct question can continue to use POST /panels/{panelId}/ask.
Do not create a study plan for an operational request against existing results. Use the panel export endpoints for “export this,” and use the summary endpoints to retrieve or re-present the current outcome. A new plan is needed only when the requested format changes what evidence must be collected.
The lifecycle is deliberately two-step:
- Preview a versioned draft. The planning model captures intent, the main source or asset, user questions, suggested questions, methods, outputs, missing inputs, and explicit confirmation questions.
- Revise the same draft until the user explicitly confirms its exact revision, then run it. The preview endpoint never starts research.
Preview or revise a plan
Endpoint: POST /api/v1/panels/{panelId}/research-plans/preview
New draft:
{
"request": "Audit this campaign website with buyers and identify messaging gaps",
"source": {
"kind": "website",
"label": "Campaign landing page",
"url": "https://example.com/campaign"
}
}
The response contains draftPlanId, revision, plan, confirmationQuestions, and nextAction. Every plan is a draft, even when status is needs_confirmation.
To answer a confirmation question or change the plan, create a new revision:
{
"draftPlanId": "3a0c66e8-c2cd-4dbc-8ca7-363a5dcb5f1b",
"revision": 1,
"refinement": "Keep this simple and compare the two buyer groups",
"answers": {
"primary-source": "Use the campaign landing page"
}
}
Draft revisions are stored durably with the panel. Stale revisions return 409 Conflict; only the draft creator may revise or confirm them.
Confirm and run the exact revision
Endpoint: POST /api/v1/panels/{panelId}/studies
{
"draftPlanId": "3a0c66e8-c2cd-4dbc-8ca7-363a5dcb5f1b",
"revision": 2,
"confirmation": {
"accepted": true,
"advancedMethodOptIn": false
}
}
The server reloads the stored revision, validates its method versions, configuration, runners, stages, and required confirmation capabilities, and queues it only after explicit acceptance. Advanced methods additionally require advancedMethodOptIn: true, but opt-in does not make an unavailable method executable. MaxDiff is available: the server builds balanced forced-choice tasks, the existing durable panel-questionnaire processor collects their locked categorical answers, and a registered deterministic calculation produces overall and per-Group rankings. Conjoint remains planned and is rejected at execution time.
The response includes a durable studyId and an immutable confirmed plan snapshot.
Plan limits are enforced twice. If the confirmed study would exceed the current Panel-answer allowance, POST /studies returns 403 with structured data.code: "PLAN_LIMIT" before the survey is queued. If an allowance is exhausted while an already queued survey is running, completed answers remain durable, remaining questions are not executed, and the study moves to status: "plan_limited" with separate completed and skipped progress plus planLimit details. This is not a completed study. Upgrade before starting a follow-up run for the remaining questions.
Study status
Endpoint: GET /api/v1/panels/{panelId}/studies/{studyId}
Returns status, per-question progress, the immutable confirmed plan, the separate server-prepared executionPlan, method stages, response/diagnostic artifacts, deterministic method calculations, and next actions. For adapter-backed methods, executionPlan contains the exact generated collection tasks while plan remains the revision the user approved. Poll this endpoint after execution rather than relying on client memory.
Clients must treat plan_limited as an explicit paywall outcome: show the upgrade action and explain that the survey stopped before all questions completed. Do not collapse it into completed, cancelled, or a generic processor failure.
Research method catalog
Endpoint: GET /api/v1/research-methods
Returns public method IDs and versions, an explicit executable boolean, availability (available, experimental, or planned), complexity, configuration JSON Schemas, stage kinds, artifact types, output types, and fallback methods. Only availability: "available" / executable: true methods can be passed to the current study runner. Internal runner identifiers are intentionally not exposed.
Flexible semantic summary
GET /api/v1/panels/{panelId}/summaryretrieves the persisted summary.POST /api/v1/panels/{panelId}/summarygenerates or refreshes it. The body acceptsforceandlength(short,standard, ordetailed).
Summary blocks are evidence contracts, not fixed widgets. Consumers may add new renderer logic without changing the underlying study. For website, image, ad, and video evidence, preserve heatmap or timeline-heatmap blocks instead of coercing them into donut charts.
List Panels
Retrieve all panels belonging to the authenticated user.
Endpoint: GET /api/v1/panels
Headers:
Authorization: Bearer minds_your_api_key
Response
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Consumer Research Panel",
"flowMode": "panel",
"createdAt": "2025-12-10T12:00:00.000Z",
"updatedAt": "2025-12-10T14:30:00.000Z",
"messageCount": 8,
"groups": [
{
"id": "group-123",
"name": "Gen Z Consumers",
"sparkCount": 5,
"sparks": [
{
"id": "spark-1",
"name": "Emma",
"discipline": "College Student",
"profileImageUrl": "https://..."
}
]
}
]
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique panel identifier |
name | string | Panel name |
flowMode | string | Always "panel" for panel flows |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last update timestamp |
messageCount | number | Total number of messages (questions + responses) |
groups | array | Mind groups attached to this panel |
groups[].sparkCount | number | Number of minds in the group |
Example Request
curl -X GET "https://getminds.ai/api/v1/panels" \
-H "Authorization: Bearer minds_your_api_key"
Create Panel
Create a new panel with optional mind groups attached.
Endpoint: POST /api/v1/panels
Headers:
Authorization: Bearer minds_your_api_key
Content-Type: application/json
Request Body
{
"name": "Product Feedback Panel",
"groupIds": ["group-123", "group-456"]
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the panel |
groupIds | array | No | Array of mind group IDs to attach to the panel |
Response
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Product Feedback Panel",
"flowMode": "panel",
"createdAt": "2025-12-10T12:00:00.000Z",
"groups": [
{
"id": "group-123",
"name": "Early Adopters",
"sparks": [
{
"id": "spark-1",
"name": "Alex",
"discipline": "Tech Enthusiast",
"profileImageUrl": "https://..."
}
]
}
]
}
}
Example Request
curl -X POST "https://getminds.ai/api/v1/panels" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Market Research Panel",
"groupIds": ["group-123", "group-456"]
}'
Error Responses
400 Bad Request - Missing name
{
"statusCode": 400,
"message": "name is required"
}
404 Not Found - One or more groupIds not found or not accessible to the caller
{
"statusCode": 404,
"message": "Groups not found: 1f2e3d4c-..."
}
Get Panel Details
Retrieve a specific panel with all its groups and message history.
Endpoint: GET /api/v1/panels/{panelId}
Headers:
Authorization: Bearer minds_your_api_key
Response
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Consumer Research Panel",
"flowMode": "panel",
"createdAt": "2025-12-10T12:00:00.000Z",
"updatedAt": "2025-12-10T14:30:00.000Z",
"groups": [
{
"id": "group-123",
"name": "Gen Z Consumers",
"sparks": [
{
"id": "spark-1",
"name": "Emma",
"discipline": "College Student",
"profileImageUrl": "https://..."
}
]
}
],
"messages": [
{
"id": "msg-1",
"role": "user",
"content": "How important is sustainability when choosing products?",
"metadata": {
"groupIds": ["group-123"]
},
"createdAt": "2025-12-10T14:00:00.000Z"
},
{
"id": "msg-2",
"role": "assistant",
"content": "How important is sustainability when choosing products?",
"metadata": {
"outputData": {
"title": "How important is sustainability when choosing products?",
"type": "scale",
"groups": [
{
"group": "Gen Z Consumers",
"value": "Very Important",
"answers": [
{
"value": "9/10",
"persona": "Emma",
"discipline": "College Student",
"message": "Sustainability is a top priority for me..."
}
]
}
]
},
"outputType": "bar"
},
"createdAt": "2025-12-10T14:00:30.000Z"
}
]
}
}
Example Request
curl -X GET "https://getminds.ai/api/v1/panels/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer minds_your_api_key"
Error Responses
403 Forbidden - Not authorized to access this panel
404 Not Found - Panel does not exist
Ask Panel Question
Send a question to all minds in the panel and receive streaming responses with aggregated results.
Endpoint: POST /api/v1/panels/{panelId}/ask
Headers:
Authorization: Bearer minds_your_api_key
Content-Type: application/json
Request Body
Basic question:
{
"question": "What features would make you switch to a competitor product?",
"groupIds": ["group-123"]
}
With attachments:
{
"question": "Please review this product design and provide feedback",
"attachments": [
{
"url": "https://example.com/design.pdf",
"name": "Product Design v2",
"type": "application/pdf"
},
{
"path": "uploads/mockup.png",
"name": "UI Mockup"
}
],
"links": [
{
"label": "https://competitor.com/product",
"id": "link-1"
}
],
"keywords": [
{
"label": "sustainable packaging",
"url": "https://example.com/article",
"id": "keyword-1"
}
]
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The question to ask all minds in the panel |
groupIds | array | No | Limit the question to specific groups (defaults to all groups) |
attachments | array | No | File attachments (PDFs, images, documents) to provide context. See file attachments below. |
links | array | No | URLs to fetch and analyze (uses Firecrawl for JS-heavy sites). Each has label (URL string) and optional id. |
keywords | array | No | Keywords with associated URLs for context. Each has label (keyword string), url (source URL), and optional id. |
model | string | No | Override the AI model used for panelist responses. Must be sent together with provider. See model override below. |
provider | string | No | AI provider for the model override: openai, anthropic, or google. Must be sent together with model. |
disableDiversityCheck | boolean | No | When true, skips the diversity-enforced regeneration loop (bigram self-similarity, value homogeneity, empty-bucket fill). Intended for ablation / benchmark runs where the orchestration layer is the variable under test. Default: false. |
sourcePolicy | string | No | auto (default) or knowledge_only. The latter forbids request attachments/links/keywords and live web search, pre-retrieves each selected Mind's knowledge, and fails closed if any Mind has no matching evidence. |
Each Mind's persisted policy is also enforced. A Mind saved as knowledge_only stays knowledge-only inside a mixed panel even when the panel request uses auto; only auto Minds may use shared web or request context.
For a durable knowledge-only request, use POST /api/v1/panels/{panelId}/runs with the same sourcePolicy. MCP ask_panel exposes the same parameter. responseMode: "queued" on /ask does not accept knowledge_only; use the durable runs endpoint instead.
Durable knowledge-only panel run
Durable runs survive client disconnects and are the recommended path for integrations. Supply a stable UUID in clientRequestId when you need safe retries. Reusing that UUID with the same normalized request returns the existing run; reusing it for different input returns 409.
curl -X POST "https://getminds.ai/api/v1/panels/{panelId}/runs" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"question": "What does your source say about classroom smartphone rules?",
"clientRequestId": "7c814f2a-2514-4db7-9e15-44c0e873caf8",
"sourcePolicy": "knowledge_only"
}'
Response: 202 Accepted
{
"data": {
"runId": "d3852cd2-1283-4e7a-a098-40bb6918f58e",
"panelId": "9220f8af-e2d2-4a38-9f36-c1ab12cc667c",
"clientRequestId": "7c814f2a-2514-4db7-9e15-44c0e873caf8",
"questionGroupId": "e68fc257-bfb6-420f-9690-e604eaf672e2",
"status": "queued",
"dispatchState": "published",
"acceptedAt": "2026-08-05T15:30:00.000Z",
"statusUrl": "/api/v1/runs/d3852cd2-1283-4e7a-a098-40bb6918f58e",
"eventsUrl": "/api/v1/runs/d3852cd2-1283-4e7a-a098-40bb6918f58e/events"
}
}
Poll statusUrl until data.status is completed, cancelled, or failed. When completed, data.assistantMessageId points to the persisted panel answer. For ordered progress and replay, request eventsUrl?after={lastSequence}; the response includes the next cursor and current runStatus.
Knowledge-only panel runs reject attachments, links, and keywords. They disable live web search and prior panel-answer context, retrieve each selected Mind independently, and fail the run with KNOWLEDGE_SOURCE_UNAVAILABLE if any selected Mind has no matching processed knowledge. Upload and process the source for every Mind before starting the run.
Other relevant errors are 409 PANEL_MINDS_NOT_READY when a selected Mind is still training or failed training, and 409 when a clientRequestId is reused with different input.
Response (Server-Sent Events)
The endpoint returns a stream of Server-Sent Events (SSE). Each event is a JSON object with a type field.
Question Classification
Before processing, the system automatically classifies your question into one of three types:
| Type | Description | Example Questions |
|---|---|---|
scale | Numeric ratings (1-5, 1-10, etc.) | "Rate this 1-5", "Score from 0-10" |
categorical | Discrete choices (yes/no, A/B/C) | "Do you agree?", "Which do you prefer: A, B, or C?" |
qualitative | Open-ended opinions | "What do you think?", "What concerns do you have?" |
For qualitative questions, responses are automatically clustered into topics (e.g., "Privacy concerns", "Cost barriers"). Each response's value field contains its assigned topic.
Event Types
1. Start Event
{"type": "start", "total": 10}
Indicates the start of processing with total number of minds.
2. Classification Event
{
"type": "classification",
"classification": {
"type": "scale",
"scaleRange": [1, 5]
}
}
Indicates how the question was classified. For scale questions, includes the detected range. For categorical questions, includes the detected options.
3. Answer Event
{
"type": "answer",
"sparkId": "spark-1",
"sparkName": "Emma",
"discipline": "College Student",
"profileImageUrl": "https://...",
"groupId": "group-123",
"groupName": "Gen Z Consumers",
"answer": "4\n\nI think this is a solid product but could improve..."
}
Sent for each mind's individual response. For scale/categorical questions, the answer starts with the rating/choice followed by reasoning.
4. Aggregating Event
{"type": "aggregating"}
Indicates AI is now aggregating all responses. For qualitative questions, this includes topic clustering.
5. Result Event
{
"type": "result",
"outputData": {
"title": "What features would make you switch to a competitor product?",
"type": "categorical",
"classification": {
"type": "categorical",
"options": ["Yes", "No", "Maybe"]
},
"groups": [
{
"group": "Gen Z Consumers",
"value": "Better Price",
"alignmentScore": 82,
"answers": [
{
"value": "Price",
"persona": "Emma",
"discipline": "College Student",
"message": "A comparable plan is 20% cheaper[0], so I would switch for better pricing.",
"imageUrl": "https://...",
"reliabilityScore": 84,
"citationSources": [
{
"id": "web-0-https://example.com/pricing",
"title": "Competitor pricing",
"url": "https://example.com/pricing",
"domain": "example.com",
"sourceType": "web"
}
],
"citationProvenance": {
"mode": "generation",
"status": "attributed",
"recordedAt": "2026-07-20T17:00:00.000Z",
"verifier": "panel-citations-v1"
}
}
]
}
]
},
"outputType": "bar"
}
Contains the aggregated results with classified responses. alignmentScore and per-answer reliabilityScore are computed before the result is returned on v1 endpoints (see Alignment scoring).
6. Done Event
{"type": "done"}
Indicates the stream is complete.
Output Data Structure
| Field | Type | Description |
|---|---|---|
title | string | The original question |
type | string | Response type: "scale", "categorical", or "qualitative" |
classification | object | Classification details (type, scaleRange, or options) |
groups | array | Aggregated responses by spark group |
groups[].group | string | Group name |
groups[].value | string | Dominant value for the group (average for scale, most common for categorical, dominant topic for qualitative) |
groups[].alignmentScore | number? | Average of per-answer reliabilityScore for the group (0–100). See Alignment scoring. Omitted when no answer in the group could be scored. |
groups[].answers | array | Individual mind responses |
groups[].answers[].value | string | Extracted value: number for scale, choice for categorical, topic for qualitative |
groups[].answers[].persona | string | Spark name |
groups[].answers[].discipline | string | Spark discipline/role |
groups[].answers[].message | string | Full response text (reasoning for scale/categorical, full answer for qualitative) |
groups[].answers[].imageUrl | string | Spark profile image URL |
groups[].answers[].reliabilityScore | number? | Per-mind reliability score (0–100): how on-character this mind's answer was against its own persona definition. See Alignment scoring. Omitted when the evaluator was skipped (short systemPrompt, empty message) or failed. |
groups[].answers[].citationSources | array? | Server-owned source identities referenced by zero-based [N] markers in message. Private Mind files have a title but no URL. Underlying knowledge text is not returned. |
groups[].answers[].citationProvenance | object? | Citation provenance. mode: "generation" means sources were attributed during the original turn; mode: "retroactive" means a historical answer was checked later against the Mind's then-current knowledge base. |
Claim-level citations
Citation fields are optional. They appear only when a response contains a factual claim tied to retrieved Mind knowledge or web evidence. A marker such as [0] points to citationSources[0]; [0,1] means both sources support the preceding claim. Validate markers against the returned array and ignore unknown indexes.
citationProvenance.status: "attributed" records generation-time source attribution; it is not a claim that a separate verifier independently proved the answer. status: "verified" is used when an existing historical answer was checked later. Consumers should preserve the distinction and must not present retroactive verification as evidence captured during the original turn.
The per-Mind answer SSE event remains clean display text and does not include unresolved citation metadata. Use the final result.outputData.groups[].answers[] objects when citation rendering is required.
Response Types Explained
Scale responses:
value: The numeric rating (e.g., "4")message: Brief reasoning for the ratinggroups[].value: Average rating across the group
Categorical responses:
value: The chosen option (e.g., "Yes", "Option A")message: Brief reasoning for the choicegroups[].value: Most common choice in the group
Qualitative responses:
value: Assigned topic/theme (e.g., "Privacy concerns", "Cost barriers")message: Full response textgroups[].value: Dominant topic in the group- Topics are automatically clustered from all responses (3-6 topics identified)
Alignment scoring
Every panel answer includes two scores on the v1 API response:
groups[].answers[].reliabilityScore(0–100, integer, optional) — per-mind score of how on-character the mind's answer is against its ownsystemPrompt. Computed by re-evaluating the response with the same evaluator used for individual spark chats, so the v1 panel value is directly comparable to single-mindreliabilityScorevalues.groups[].alignmentScore(0–100, integer, optional) — average of per-answerreliabilityScorefor that group. The UI surfaces this as the per-group Alignment indicator (High / Medium / Low).
Label bands used by the UI (not in the payload, included here so API consumers can match):
| Band | Range |
|---|---|
| High | 67–100 |
| Medium | 34–66 |
| Low | 0–33 |
When fields are omitted: the evaluator skips answers where the mind's systemPrompt is shorter than 20 characters, where the answer message is empty, or when the evaluator call itself fails. If every answer in a group is skipped, that group's alignmentScore is also omitted.
Timing: on the v1 endpoints, scoring runs synchronously before the response is returned, so the scores are present in the same payload as the rest of outputData. This adds a few seconds of latency on top of panel generation; consumers that need a faster panel result without alignment should batch-evaluate downstream instead of relying on the inline score.
Status: this is a temporary stand-in for a future group-alignment metric (closeness to empirical research findings). The field names will be preserved when that lands; the semantics of alignmentScore may change.
File Attachments
You can attach files, links, and keywords to provide context for panel questions. Minds will receive the processed content before answering.
Attachment Types
1. File Attachments (attachments)
Upload documents, PDFs, images, spreadsheets for analysis:
{
"question": "What improvements would you suggest for this product spec?",
"attachments": [
{
"url": "https://example.com/product-spec.pdf",
"name": "Product Specification v2.1",
"type": "application/pdf"
},
{
"path": "uploads/user-research.docx",
"name": "User Research Findings"
}
]
}
Supported formats:
- Documents: PDF, DOCX, TXT, MD
- Images: PNG, JPG, WEBP (with OCR)
- Spreadsheets: CSV, XLSX
File sources:
url: External URL (downloaded and processed)path: Supabase storage path (auto-signed and processed)
2. Link Attachments (links)
Fetch and analyze web pages (uses Firecrawl for JS-heavy sites + screenshots):
{
"question": "Compare our pricing to these competitors",
"links": [
{ "label": "https://competitor-a.com/pricing", "id": "link-1" },
{ "label": "https://competitor-b.com/pricing", "id": "link-2" }
]
}
Features:
- JavaScript rendering (Firecrawl)
- Screenshot capture for visual context
- Markdown extraction
- Automatic content truncation (3000 chars per link if multiple, 15000 if single)
3. Keyword Context (keywords)
Provide keywords with source URLs for additional context:
{
"question": "How can we improve sustainability?",
"keywords": [
{
"label": "circular economy",
"url": "https://en.wikipedia.org/wiki/Circular_economy",
"id": "kw-1"
},
{
"label": "carbon neutral packaging",
"url": "https://example.com/carbon-neutral-guide",
"id": "kw-2"
}
]
}
Complete Example with Attachments
curl -X POST "https://getminds.ai/api/v1/panels/panel-id/ask" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"question": "Based on this product design and competitor analysis, what features should we prioritize?",
"groupIds": ["product-managers", "designers"],
"attachments": [
{
"url": "https://example.com/product-design-v3.pdf",
"name": "Product Design v3",
"type": "application/pdf"
}
],
"links": [
{ "label": "https://competitor.com/features" }
],
"keywords": [
{
"label": "user experience best practices",
"url": "https://uxdesign.com/best-practices"
}
]
}'
Processing:
- Files are analyzed in parallel (PDFs → text extraction, images → OCR/vision)
- Links are fetched with Firecrawl (JS rendering + screenshots)
- Content is injected into the question context for all minds
- Failed attachments are gracefully handled with fallback messages
Tips:
- Attach only relevant files (each adds processing time)
- Use links for dynamic web content
- Use keywords for additional web context
- File processing timeout: 30s per file
- Link fetching timeout: 15s per URL
Example Request
curl -X POST "https://getminds.ai/api/v1/panels/550e8400-e29b-41d4-a716-446655440000/ask" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"question": "On a scale of 1-10, how likely are you to recommend this product?"
}'
Example: JavaScript EventSource
const eventSource = new EventSource(
'https://getminds.ai/api/v1/panels/{panelId}/ask',
{
headers: {
'Authorization': 'Bearer minds_your_api_key',
'Content-Type': 'application/json'
}
}
);
// Note: For POST requests with SSE, use fetch with ReadableStream
const response = await fetch('https://getminds.ai/api/v1/panels/{panelId}/ask', {
method: 'POST',
headers: {
'Authorization': 'Bearer minds_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
question: 'How satisfied are you with the current pricing?'
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const event = JSON.parse(line.slice(6));
console.log('Event:', event.type, event);
}
}
}
Error Responses
400 Bad Request - Missing question or no groups attached
{
"statusCode": 400,
"message": "question is required"
}
{
"statusCode": 400,
"message": "No groups attached to this panel"
}
{
"statusCode": 400,
"message": "No minds in panel groups"
}
403 Forbidden - Not authorized to access this panel
404 Not Found - Panel does not exist
Model Override
By default, panel responses use your team's preferred provider when one is configured and eligible, otherwise the product default. You can override the model and provider per request to run experiments across model families:
curl -X POST "https://getminds.ai/api/v1/panels/{panelId}/ask" \
-H "Authorization: Bearer minds_…_key" \
-H "Content-Type: application/json" \
-d '{
"question": "Rate this 1-5",
"model": "gpt-4o",
"provider": "openai"
}'
Supported providers: openai, anthropic, google. For panel requests, model and provider must be sent together. If only one is sent, the API returns 400 Bad Request. Per-request overrides take precedence over the team provider preference.
Disable Diversity Check
The panel orchestrator runs a post-generation diversity-enforced regeneration loop (bigram self-similarity check, value-homogeneity detection, empty-bucket fill) before aggregation. This is the L4 layer of the panel recipe.
For ablation studies and benchmark runs where you want to isolate the contribution of this layer, pass disableDiversityCheck: true:
curl -X POST "https://getminds.ai/api/v1/panels/{panelId}/ask" \
-H "Authorization: Bearer minds_…_key" \
-H "Content-Type: application/json" \
-d '{
"question": "What features matter most to you?",
"disableDiversityCheck": true
}'
With the flag enabled, panelist responses are returned exactly as initially generated — no second-pass regeneration is triggered, even if responses overlap heavily. Classification (L3), per-spark RAG (L2), and aggregation (L5) still run normally. Cost-savings: ~5–25% fewer LLM calls per panel question, depending on how many sparks the diversity check would have flagged.
When to use: Method comparisons, A/B tests of orchestration layers, reproducing baseline behavior. Production panels should leave this off (default).
Export Panel Results
Generate a structured report of all panel results in Markdown format.
Endpoint: POST /api/v1/panels/{panelId}/export
Headers:
Authorization: Bearer minds_your_api_key
Content-Type: application/json
Request Body
{
"format": "md"
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | Export format. Currently only "md" (Markdown) is supported. Default: "md" |
Response
{
"data": {
"format": "md",
"content": "# Panel Report: Consumer Research Panel\n\n## Executive Summary\n\nThis panel survey gathered insights from 15 participants across 3 consumer groups...\n\n## Methodology\n\n- 3 groups, 15 participants\n- 5 questions asked\n\n## Results by Question\n\n### Q1: How important is sustainability when choosing products?\n\n**Type:** scale\n\n#### Gen Z Consumers (dominant: Very Important)\n\n..."
}
}
Report Structure
The generated report includes:
- Executive Summary - 2-3 paragraph overview of key findings
- Methodology - Groups, participants, and structure
- Results by Question - Cross-group comparison with key insights and quotes
- Cross-Group Analysis - Patterns and trends across groups
- Conclusions & Recommendations - Actionable insights
Example Request
curl -X POST "https://getminds.ai/api/v1/panels/550e8400-e29b-41d4-a716-446655440000/export" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"format": "md"
}'
Error Responses
403 Forbidden - Not authorized to access this panel
404 Not Found - Panel does not exist
Check Export Status
Check the status of a panel export job. If no jobId is provided, returns the status of the most recent export.
Endpoint: GET /api/v1/panels/{panelId}/export-status
Headers:
Authorization: Bearer minds_your_api_key
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
jobId | string | No | Specific job ID. If omitted, returns the most recent export job |
Response
{
"data": {
"status": "completed",
"downloadUrl": "/api/v1/panels/{panelId}/export-download?jobId=job-123"
}
}
Status Values
| Status | Description |
|---|---|
queued | Export job is waiting to be processed |
processing | Export is being generated (includes progress field, 0-100) |
completed | Export is ready for download (includes downloadUrl field) |
failed | Export failed (includes error field with reason) |
Example Request
curl -X GET "https://getminds.ai/api/v1/panels/{panelId}/export-status?jobId=job-123" \
-H "Authorization: Bearer minds_your_api_key"
Error Responses
403 Forbidden - Not authorized to access this panel
404 Not Found - Panel or job does not exist
Download Export
Download the exported panel report as a PDF file.
Endpoint: GET /api/v1/panels/{panelId}/export-download
Headers:
Authorization: Bearer minds_your_api_key
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
jobId | string | Yes | The export job ID (from export-status response) |
Response
Returns a PDF file with appropriate headers:
Content-Type: application/pdfContent-Disposition: attachment; filename="Panel-Report.pdf"
Example Request
curl -X GET "https://getminds.ai/api/v1/panels/{panelId}/export-download?jobId=job-123" \
-H "Authorization: Bearer minds_your_api_key" \
-o panel-report.pdf
Error Responses
400 Bad Request - Missing jobId parameter or job is not yet completed
403 Forbidden - Not authorized to access this panel
404 Not Found - Panel or job does not exist
Workflow Example
Here is a complete workflow for creating and using a panel:
# 1. Create spark groups first (using Sparks API)
# Assume you have created groups with IDs: group-genz, group-millennials
# 2. Create a panel with those groups
curl -X POST "https://getminds.ai/api/v1/panels" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Product Pricing Research",
"groupIds": ["group-genz", "group-millennials"]
}'
# Response: { "data": { "id": "panel-123", ... } }
# 3. Ask questions to the panel
curl -X POST "https://getminds.ai/api/v1/panels/panel-123/ask" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"question": "What price point would you consider fair for this product?"
}'
# 4. Ask another question
curl -X POST "https://getminds.ai/api/v1/panels/panel-123/ask" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"question": "How does this compare to competitor pricing?"
}'
# 5. Export the results as a report
curl -X POST "https://getminds.ai/api/v1/panels/panel-123/export" \
-H "Authorization: Bearer minds_your_api_key" \
-H "Content-Type: application/json" \
-d '{"format": "md"}'
# 6. Check export status (poll until completed)
curl -X GET "https://getminds.ai/api/v1/panels/panel-123/export-status" \
-H "Authorization: Bearer minds_your_api_key"
# Response: { "data": { "status": "completed", "downloadUrl": "/api/v1/panels/panel-123/export-download?jobId=..." } }
# 7. Download the PDF
curl -X GET "https://getminds.ai/api/v1/panels/panel-123/export-download?jobId=job-123" \
-H "Authorization: Bearer minds_your_api_key" \
-o panel-report.pdf
Error Codes Summary
| Code | Description |
|---|---|
| 400 | Bad Request - Missing required fields or invalid data |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Not authorized to access this panel |
| 404 | Not Found - Panel does not exist |
| 500 | Internal Server Error - Server-side error |
Next Steps
- Create minds to populate your panel groups
- Learn about authentication
- Review errors and limits