Minds Team

Panels API

Create and manage AI panels for surveying groups of minds with structured response aggregation.

Panels API

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

ConceptDescription
PanelA container for surveying multiple mind groups with questions
Mind GroupA collection of minds that respond together (e.g., "Gen Z Users", "Senior Developers")
QuestionA prompt sent to all minds in the panel's groups
Aggregated ResponseAI-classified and grouped responses with scale or categorical values

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

FieldTypeDescription
idstringUnique panel identifier
namestringPanel name
flowModestringAlways "panel" for panel flows
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last update timestamp
messageCountnumberTotal number of messages (questions + responses)
groupsarrayMind groups attached to this panel
groups[].sparkCountnumberNumber 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

ParameterTypeRequiredDescription
namestringYesName of the panel
groupIdsarrayNoArray 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 or invalid group IDs

{
  "statusCode": 400,
  "message": "name is required"
}
{
  "statusCode": 400,
  "message": "One or more groups not found"
}

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

ParameterTypeRequiredDescription
questionstringYesThe question to ask all minds in the panel
groupIdsarrayNoLimit the question to specific groups (defaults to all groups)
attachmentsarrayNoFile attachments (PDFs, images, documents) to provide context. See file attachments below.
linksarrayNoURLs to fetch and analyze (uses Firecrawl for JS-heavy sites). Each has label (URL string) and optional id.
keywordsarrayNoKeywords with associated URLs for context. Each has label (keyword string), url (source URL), and optional id.
modelstringNoOverride the AI model used for panelist responses. See model override below.
providerstringNoAI provider for the model override: openai, anthropic, or google. Auto-detected from model name when possible.
disableDiversityCheckbooleanNoWhen 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.

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:

TypeDescriptionExample Questions
scaleNumeric ratings (1-5, 1-10, etc.)"Rate this 1-5", "Score from 0-10"
categoricalDiscrete choices (yes/no, A/B/C)"Do you agree?", "Which do you prefer: A, B, or C?"
qualitativeOpen-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": "I would switch if a competitor offered better pricing...",
            "imageUrl": "https://...",
            "reliabilityScore": 84
          }
        ]
      }
    ]
  },
  "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

FieldTypeDescription
titlestringThe original question
typestringResponse type: "scale", "categorical", or "qualitative"
classificationobjectClassification details (type, scaleRange, or options)
groupsarrayAggregated responses by spark group
groups[].groupstringGroup name
groups[].valuestringDominant value for the group (average for scale, most common for categorical, dominant topic for qualitative)
groups[].alignmentScorenumber?Average of per-answer reliabilityScore for the group (0–100). See Alignment scoring. Omitted when no answer in the group could be scored.
groups[].answersarrayIndividual mind responses
groups[].answers[].valuestringExtracted value: number for scale, choice for categorical, topic for qualitative
groups[].answers[].personastringSpark name
groups[].answers[].disciplinestringSpark discipline/role
groups[].answers[].messagestringFull response text (reasoning for scale/categorical, full answer for qualitative)
groups[].answers[].imageUrlstringSpark profile image URL
groups[].answers[].reliabilityScorenumber?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.

Response Types Explained

Scale responses:

  • value: The numeric rating (e.g., "4")
  • message: Brief reasoning for the rating
  • groups[].value: Average rating across the group

Categorical responses:

  • value: The chosen option (e.g., "Yes", "Option A")
  • message: Brief reasoning for the choice
  • groups[].value: Most common choice in the group

Qualitative responses:

  • value: Assigned topic/theme (e.g., "Privacy concerns", "Cost barriers")
  • message: Full response text
  • groups[].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 own systemPrompt. 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-mind reliabilityScore values.
  • groups[].alignmentScore (0–100, integer, optional) — average of per-answer reliabilityScore for 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):

BandRange
High67–100
Medium34–66
Low0–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 the model configured in the panel's Langfuse prompt (typically Claude). 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. The provider is auto-detected for common model name patterns (gpt-*, o1-*, o3-*, o4-* → openai; claude-* → anthropic; gemini-* → google), but can be specified explicitly to disambiguate.

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

ParameterTypeRequiredDescription
formatstringNoExport 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:

  1. Executive Summary - 2-3 paragraph overview of key findings
  2. Methodology - Groups, participants, and structure
  3. Results by Question - Cross-group comparison with key insights and quotes
  4. Cross-Group Analysis - Patterns and trends across groups
  5. 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

ParameterTypeRequiredDescription
jobIdstringNoSpecific 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

StatusDescription
queuedExport job is waiting to be processed
processingExport is being generated (includes progress field, 0-100)
completedExport is ready for download (includes downloadUrl field)
failedExport 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

ParameterTypeRequiredDescription
jobIdstringYesThe export job ID (from export-status response)

Response

Returns a PDF file with appropriate headers:

  • Content-Type: application/pdf
  • Content-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

CodeDescription
400Bad Request - Missing required fields or invalid data
401Unauthorized - Invalid or missing API key
403Forbidden - Not authorized to access this panel
404Not Found - Panel does not exist
500Internal Server Error - Server-side error

Next Steps