---
title: "Chat API"
description: "Interact with your minds through chat completions and multi-turn conversations. Covers stateful chats, stateless completions, attachments, and tool calling."
---

# Chat API

Send messages to your minds and receive AI-generated responses. The Chat API supports both stateless completions and stateful multi-turn conversations with automatic history management.

## Stateful Chats (Recommended)

Create persistent conversations where the server manages history, context compression, and rolling summaries automatically. No need to send the full message history with each request.

### Create a Chat

Create a new stateful conversation linked to a mind.

**Endpoint:** `POST /api/v1/chats`

**Headers:**

```text
Authorization: Bearer minds_your_api_key
Content-Type: application/json
```

**Request Body:**

```json
{
  "name": "My Conversation",
  "sparkId": "your-mind-id"
}
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        name
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Display name for the chat (default: "API Chat")
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sparkId
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      The mind to chat with. If omitted, assign a mind later.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        description
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Optional description
    </td>
  </tr>
</tbody>
</table>

**Response (201):**

```json
{
  "data": {
    "id": "601af953-3837-49c1-a31e-4fdbfa82ac04",
    "name": "My Conversation",
    "description": null,
    "createdAt": "2026-04-04T12:45:24.078Z",
    "sparks": [
      {
        "id": "4774888e-0a03-40d7-979b-39b47c4c049c",
        "name": "Ada Lovelace",
        "discipline": "mathematician and computer scientist"
      }
    ]
  }
}
```

### Send a Message

Send a message to an existing chat. The server automatically handles conversation history, context window compression, and rolling summaries.

**Endpoint:** `POST /api/v1/chats/{chatId}/messages`

**Headers:**

```text
Authorization: Bearer minds_your_api_key
Content-Type: application/json
```

**Request Body:**

```json
{
  "content": "What are the latest advancements in solar panel technology?"
}
```

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        content
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      The message text (alternatively use <code>
        message
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        model
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Override the AI model for this message. Must be sent together with <code>
        provider
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        provider
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      AI provider for the model override: <code>
        openai
      </code>
      
      , <code>
        anthropic
      </code>
      
      , or <code>
        google
      </code>
      
      . Must be sent together with <code>
        model
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        endUserName
      </code>
    </td>
    
    <td>
      string|null
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Optional display name for the actual end user in this request. If omitted, <code>
        null
      </code>
      
      , or empty, Minds addresses the user neutrally and does not infer a name from the API-key/account owner. Aliases: <code>
        userDisplayName
      </code>
      
      , <code>
        userName
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

Stateful chat model selection uses this order: per-request override, then your team's preferred provider if one is configured and eligible, then the product default. On this endpoint, partial overrides are rejected with `400 Bad Request`; send both `model` and `provider` or omit both.

**Response:**

```json
{
  "content": "Recent advancements in solar panel technology include perovskite cells with 30%+ efficiency...",
  "messageId": "cmnkbsddh00033v01ptk9t4et"
}
```

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        content
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      The mind's response
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        messageId
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      Unique ID of the saved message
    </td>
  </tr>
</tbody>
</table>

### Multi-Turn Example

With stateful chats, you just send the new message each time. The server remembers everything:

```bash
# Step 1: Create a chat
CHAT=$(curl -s -X POST "https://getminds.ai/api/v1/chats" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Research Session", "sparkId": "your-mind-id" }')

CHAT_ID=$(echo $CHAT | jq -r '.data.id')

# Step 2: Send messages (server manages history automatically)
curl -X POST "https://getminds.ai/api/v1/chats/$CHAT_ID/messages" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "content": "What are the top marketing trends?" }'

# Step 3: Follow up (the mind remembers the previous exchange)
curl -X POST "https://getminds.ai/api/v1/chats/$CHAT_ID/messages" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Which of those would work best on a small budget?" }'
```

**How it works under the hood:**

- Every message is persisted to the database
- The last 8 messages are sent in full context
- Older messages are compressed into a rolling LLM summary
- Conversations can run for weeks/months without hitting context limits

---

## Stateless Completions

For single requests or when you want to manage conversation history yourself.

### Send Message

Send messages to a mind and receive responses.

**Endpoint:** `POST /api/v1/minds/{mindId}/completion`

**Headers:**

```text
Authorization: Bearer minds_your_api_key
Content-Type: application/json
```

### Request Body

```json
{
  "messages": [
    {
      "role": "user",
      "content": "What are the latest advancements in solar panel technology?"
    }
  ]
}
```

### Parameters

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        messages
      </code>
    </td>
    
    <td>
      array
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Array of message objects (<code>
        user
      </code>
      
      , <code>
        assistant
      </code>
      
      , or <code>
        tool
      </code>
      
      ). Omit the field entirely or send an empty array to trigger the greeting bootstrap (see <em>
        Initial Message
      </em>
      
       below).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        messages[].role
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      Either <code>
        "user"
      </code>
      
      , <code>
        "assistant"
      </code>
      
      , or <code>
        "tool"
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        messages[].content
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      The message text. Must be a non-empty string for <code>
        user
      </code>
      
       messages (whitespace is rejected with <code>
        400
      </code>
      
      ). Omit for <code>
        tool
      </code>
      
       role and use <code>
        tool_call_id
      </code>
      
       + <code>
        content
      </code>
      
       instead.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        model
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Override the AI model used for this request. See <a href="#model-override">
        model override
      </a>
      
       below.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        provider
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      AI provider for the model override: <code>
        openai
      </code>
      
      , <code>
        anthropic
      </code>
      
      , or <code>
        google
      </code>
      
      . Auto-detected from model name when possible.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        endUserName
      </code>
    </td>
    
    <td>
      string|null
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Optional display name for the actual end user in this request. If omitted, <code>
        null
      </code>
      
      , or empty, Minds addresses the user neutrally and does not infer a name from the API-key/account owner. Aliases: <code>
        userDisplayName
      </code>
      
      , <code>
        userName
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        language
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Hint for response language. Supported: <code>
        en
      </code>
      
      , <code>
        de
      </code>
      
      , <code>
        es
      </code>
      
      , <code>
        fr
      </code>
      
      , <code>
        zh
      </code>
      
      , <code>
        tr
      </code>
      
      , <code>
        ar
      </code>
      
      , <code>
        ja
      </code>
      
      , <code>
        ko
      </code>
      
      . Strong personas (e.g. clones of public figures with a fixed native language) may continue to respond in their persona's language.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        generateImage
      </code>
    </td>
    
    <td>
      boolean
    </td>
    
    <td>
      No
    </td>
    
    <td>
      When <code>
        true
      </code>
      
      , enables AI image generation in the response if contextually appropriate
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        response_format
      </code>
    </td>
    
    <td>
      object
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Request structured output. See <a href="#structured-output">
        structured output
      </a>
      
       below.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tools
      </code>
    </td>
    
    <td>
      array
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Array of user-defined tool definitions. See <a href="#tool-calling">
        tool calling
      </a>
      
       below.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tool_choice
      </code>
    </td>
    
    <td>
      string|object
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Control tool calling behavior. See <a href="#tool-choice-modes">
        tool choice modes
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parallel_tool_calls
      </code>
    </td>
    
    <td>
      boolean
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Allow multiple tool calls per turn (default: <code>
        true
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sourcePolicy
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      <code>
        auto
      </code>
      
       (default) or <code>
        knowledge_only
      </code>
      
      . <code>
        knowledge_only
      </code>
      
       retrieves processed Mind knowledge before generation, disables internal web/link/image tools, and rejects request attachments. When no processed knowledge matches, the Mind answers from its persona and the response reports <code>
        metadata.knowledgeRetrieval.status: "fallback"
      </code>
      
      , so check that field when evidence is required.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        citationMarkers
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      <code>
        inline
      </code>
      
       (default) or <code>
        none
      </code>
      
      . Controls whether <code>
        content
      </code>
      
       carries inline <code>
        [[CITE:n]]
      </code>
      
       claim-citation markers. Use <code>
        none
      </code>
      
       if you do not render citations; <code>
        metadata.ragCitations
      </code>
      
       still lists the verified sources. See <a href="#inline-citation-markers">
        inline citation markers
      </a>
      
      .
    </td>
  </tr>
</tbody>
</table>

If the Mind is saved with `sourcePolicy: "knowledge_only"`, that setting is always enforced. Sending `sourcePolicy: "auto"` cannot downgrade it.

### Knowledge-only completion

Use this after the uploaded knowledge item reports `readyForRetrieval: true`:

```json
{
  "sourcePolicy": "knowledge_only",
  "messages": [{ "role": "user", "content": "What does the study say about classroom smartphone rules?" }]
}
```

This mode is deliberately fail-closed:

- The model receives only the latest user question, the Mind's persona prompt, and the retrieved Mind-knowledge chunks. Earlier assistant answers are excluded so they cannot become an unverified source.
- Internal web, link-analysis, image, and user-provided tools are disabled. Request attachments are rejected; upload them to Mind knowledge and wait for processing instead.
- A missing user question returns `400`. If no processed knowledge matches above the retrieval threshold, the Mind still answers from its persona and `metadata.knowledgeRetrieval.status` is `"fallback"`; treat that as "no supporting evidence" in your integration.
- Successful responses expose a source-safe retrieval summary. Private storage paths and raw file contents are never returned.

```json
{
  "messageId": "msg_550e840029b141d4a716446655440000",
  "content": "The study describes classroom smartphone rules as ...",
  "metadata": {
    "sourcePolicy": "knowledge_only",
    "knowledgeRetrieval": {
      "status": "grounded",
      "chunksFound": 4,
      "sourceCount": 1,
      "sources": [
        { "title": "teacher-archetypes.pdf", "sourceType": "mind_knowledge" }
      ]
    }
  }
}
```

`knowledgeRetrieval.sources` contains deduplicated display titles, not downloadable file URLs. `chunksFound` is the number of retrieved chunks used for that answer; it is not the total embedding count reported by the knowledge-status endpoint.

### Response

```json
{
  "messageId": "msg_550e840029b141d4a716446655440000",
  "content": "Recent advancements in solar panel technology include perovskite cells with 30%+ efficiency, bifacial panels that capture light from both sides, and integrated storage systems...",
  "metadata": {
    "ragCitations": [
      {
        "id": "abc123",
        "displaySource": "Mind knowledge",
        "similarity": 0.89
      }
    ]
  }
}
```

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        messageId
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      Unique message identifier for tracking
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        content
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      The mind's response text (JSON string when using structured output)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parsed
      </code>
    </td>
    
    <td>
      object
    </td>
    
    <td>
      Parsed JSON object (only present when using <code>
        response_format
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tool_calls
      </code>
    </td>
    
    <td>
      array
    </td>
    
    <td>
      Array of tool call requests (only present when user-defined tools are called). Each has: <code>
        id
      </code>
      
      , <code>
        name
      </code>
      
      , <code>
        arguments
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metadata
      </code>
    </td>
    
    <td>
      object
    </td>
    
    <td>
      Optional metadata (citations, images)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metadata.ragCitations
      </code>
    </td>
    
    <td>
      array
    </td>
    
    <td>
      Verified knowledge sources and web search results used in the response. Inline <code>
        [[CITE:n]]
      </code>
      
       markers in <code>
        content
      </code>
      
       index into this array (0-based).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metadata.sourcePolicy
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      Present as <code>
        knowledge_only
      </code>
      
       for a successful fail-closed knowledge-only response.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metadata.knowledgeRetrieval
      </code>
    </td>
    
    <td>
      object
    </td>
    
    <td>
      Grounding status, retrieved chunk count, source count, and safe source titles for a knowledge-only response.
    </td>
  </tr>
</tbody>
</table>

### Inline citation markers

When a Mind grounds a claim in its knowledge or a web source, the claim in `content` is followed by an inline marker such as `[[CITE:0]]` or `[[CITE:0,2]]`. Each number is a 0-based index into `metadata.ragCitations`; the marker sits directly after the claim it supports, before the closing punctuation.

```text
Solar adoption in Germany grew 14% year over year[[CITE:0]]. Perovskite cells now exceed 30% efficiency[[CITE:1]].
```

Render the markers as footnotes or citation chips, or strip them with `/\[\[CITE:[^\]]*\]\]/g`. If your integration does not render citations at all, send `"citationMarkers": "none"` in the request: `content` is then returned as plain prose and `metadata.ragCitations` still lists the verified sources, so you can print a source list below the answer.

Markers only appear when the claim verifier attributes at least one source. Answers without grounding, structured-output responses, and image-only responses never carry markers.

## Single Message Example

Ask a single question:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "What are the top 3 marketing trends for 2025?"
      }
    ]
  }'
```

## Multi-Turn Conversation

Maintain conversation context by including previous messages:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "What are the top marketing trends?"
      },
      {
        "role": "assistant",
        "content": "The top trends are AI personalization, short-form video, and community building..."
      },
      {
        "role": "user",
        "content": "How can I implement AI personalization on a budget?"
      }
    ]
  }'
```

**Tips for Multi-Turn Conversations:**

- Include the full conversation history in each request
- Order matters: messages should be in chronological order
- Alternate between `user` and `assistant` roles
- The last message should always be from `user`

## File Attachments

Attach files, documents, images, and links to provide context for your minds. Minds receive the processed content as part of the conversation.

### Attaching Files

Add files via the `metadata.attachedFiles` array in your user message:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "Please review this document and summarize the key points",
        "metadata": {
          "attachedFiles": [
            {
              "url": "https://example.com/quarterly-report.pdf",
              "name": "Q4 2025 Report",
              "type": "application/pdf"
            },
            {
              "path": "uploads/meeting-notes.docx",
              "name": "Strategy Meeting Notes"
            }
          ]
        }
      }
    ]
  }'
```

### Attachment Format

Each attachment object supports:

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        url
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No*
    </td>
    
    <td>
      External URL to file (HTTP/HTTPS)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        path
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No*
    </td>
    
    <td>
      Supabase storage path (auto-signed)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        name
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Display name for the file
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        type
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      MIME type (e.g., <code>
        application/pdf
      </code>
      
      , <code>
        image/png
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        description
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Optional description
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        transcription
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Pre-transcribed audio/video content
    </td>
  </tr>
</tbody>
</table>

**Note:** Provide either `url` OR `path`, not both.

### Supported File Types

**Documents:**

- PDF (`.pdf`) - Text extraction + OCR for scanned pages
- Word (`.docx`) - Full text extraction
- Text (`.txt`, `.md`) - Direct text content
- CSV/Excel (`.csv`, `.xlsx`) - Table extraction

**Images:**

- PNG, JPG, WEBP - OCR + visual analysis
- Vision capabilities for image understanding

**External URLs:**

- Web pages fetched with Firecrawl (JS rendering + screenshots)
- Automatic markdown conversion

### Processing

Files are automatically processed before being sent to the mind:

1. **Download** - Files fetched from URL or Supabase storage
2. **Extract** - Content extracted (text from PDFs, OCR from images, etc.)
3. **Inject** - Processed content added to conversation context
4. **Response** - Mind sees both your message and the file content

**Processing limits:**

- Timeout: 30 seconds per file
- Files processed in parallel
- Failed files show graceful fallback messages

### Multiple File Example

```json
{
  "messages": [
    {
      "role": "user",
      "content": "Compare these two proposals and recommend which one to pursue",
      "metadata": {
        "attachedFiles": [
          {
            "url": "https://example.com/proposal-a.pdf",
            "name": "Proposal A - Cloud Migration",
            "type": "application/pdf"
          },
          {
            "url": "https://example.com/proposal-b.pdf",
            "name": "Proposal B - On-Prem Upgrade",
            "type": "application/pdf"
          },
          {
            "path": "uploads/budget-analysis.xlsx",
            "name": "Budget Comparison"
          }
        ]
      }
    }
  ]
}
```

### File Attachments in Conversation History

When continuing a conversation with file attachments, include the original message with attachments in the history:

```json
{
  "messages": [
    {
      "role": "user",
      "content": "Analyze this sales data",
      "metadata": {
        "attachedFiles": [
          {
            "url": "https://example.com/sales-q4.csv",
            "name": "Q4 Sales Data"
          }
        ]
      }
    },
    {
      "role": "assistant",
      "content": "Based on the Q4 sales data, I can see that revenue increased by 23% compared to Q3..."
    },
    {
      "role": "user",
      "content": "What were the top 3 performing products?"
    }
  ]
}
```

**Note:** Files are only processed once when first attached. Subsequent messages in the same conversation reference the already-processed content.

### Web Links

For web pages and external content, use the `url` field:

```json
{
  "messages": [
    {
      "role": "user",
      "content": "Summarize the key findings from this research paper",
      "metadata": {
        "attachedFiles": [
          {
            "url": "https://arxiv.org/pdf/2103.12345.pdf",
            "name": "AI Research Paper",
            "type": "application/pdf"
          }
        ]
      }
    }
  ]
}
```

**For web pages specifically:**

- JavaScript-heavy sites are rendered with Firecrawl
- Screenshots captured for visual context
- Content converted to clean markdown

### Error Handling

If file processing fails:

- Mind receives a fallback message indicating the file was attached but processing failed
- Conversation continues normally
- Timeout errors show `[Processing timeout - file may be too large]`
- Other errors show `[Processing failed - file uploaded but analysis unavailable]`

This ensures minds are aware of attempted attachments even if processing fails.

## Initial Message (Greeting)

If you send an empty messages array or no messages, the mind will introduce itself:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": []
  }'
```

Response:

```json
{
  "content": "Hi! I'm Sarah, a marketing director with 15 years of experience in B2B SaaS. I specialize in growth marketing and data-driven strategies. What can I help you with today?"
}
```

## Model Override

You can optionally override the AI model used for a stateless completion request by passing the `model` parameter. This is useful for benchmarking, cost optimization, or testing different model behaviors. Stateful chat and panel endpoints use stricter override validation: send both `model` and `provider` together.

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "What are your thoughts on sustainable packaging?"
      }
    ],
    "model": "gpt-4o-mini"
  }'
```

When no `model` is specified, the server default is used.

### Providers

<table>
<thead>
  <tr>
    <th>
      Provider
    </th>
    
    <th>
      Value
    </th>
    
    <th>
      Example Models
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      OpenAI
    </td>
    
    <td>
      <code>
        openai
      </code>
    </td>
    
    <td>
      <code>
        gpt-5.6-sol
      </code>
      
      , <code>
        gpt-5.6-terra
      </code>
      
      , <code>
        gpt-5.6-luna
      </code>
      
      , <code>
        gpt-5.4
      </code>
      
      , <code>
        gpt-5-mini
      </code>
      
      , <code>
        gpt-4o
      </code>
      
      , <code>
        gpt-4o-mini
      </code>
      
      , <code>
        o3
      </code>
      
      , <code>
        o3-pro
      </code>
      
      , <code>
        o3-mini
      </code>
      
      , <code>
        o4-mini
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Anthropic
    </td>
    
    <td>
      <code>
        anthropic
      </code>
    </td>
    
    <td>
      <code>
        claude-fable-5
      </code>
      
      , <code>
        claude-opus-5
      </code>
      
      , <code>
        claude-sonnet-5
      </code>
      
      , <code>
        claude-haiku-4-5-20251001
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Google
    </td>
    
    <td>
      <code>
        google
      </code>
    </td>
    
    <td>
      <code>
        gemini-3.7-flash
      </code>
      
      , <code>
        gemini-3.5-flash-lite
      </code>
    </td>
  </tr>
</tbody>
</table>

You can pass any model string supported by the provider. The provider is auto-detected from common model name prefixes (`claude-` → Anthropic, `gemini-` → Google, `gpt-`/`o1`/`o3`/`o4` → OpenAI).

> **Retired model IDs keep working.** When a model is superseded, its old ID is not rejected — the API transparently forwards it to the current replacement (e.g. a request pinning `claude-sonnet-4-6` runs on the current Claude Sonnet). You don't need to change your integration on our release schedule, but we recommend moving to a current ID when convenient.

For models with ambiguous names, specify the `provider` explicitly:

```json
{
  "messages": [...],
  "model": "my-custom-fine-tune",
  "provider": "openai"
}
```

If the provider cannot be determined, the API returns a `400 Bad Request` error asking you to specify it.

## Structured Output

Request guaranteed JSON responses that match a specific schema using the `response_format` parameter. This follows the OpenAI-style structured output pattern and is useful for extracting structured data from conversations.

### JSON Schema Mode

Force the model to output valid JSON matching your schema:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "Analyze the sentiment of this text: I love this product, it exceeded all my expectations!"
      }
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "sentiment_analysis",
        "description": "Sentiment analysis result",
        "schema": {
          "type": "object",
          "properties": {
            "sentiment": {
              "type": "string",
              "enum": ["positive", "negative", "neutral"]
            },
            "confidence": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            },
            "keywords": {
              "type": "array",
              "items": { "type": "string" }
            }
          },
          "required": ["sentiment", "confidence", "keywords"]
        }
      }
    }
  }'
```

Response:

```json
{
  "content": "{\"sentiment\": \"positive\", \"confidence\": 0.95, \"keywords\": [\"love\", \"exceeded\", \"expectations\"]}",
  "parsed": {
    "sentiment": "positive",
    "confidence": 0.95,
    "keywords": ["love", "exceeded", "expectations"]
  }
}
```

### JSON Object Mode

Force JSON output without schema validation:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "List 3 marketing ideas as JSON"
      }
    ],
    "response_format": {
      "type": "json_object"
    }
  }'
```

### Response Format Types

<table>
<thead>
  <tr>
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        text
      </code>
    </td>
    
    <td>
      Default text output (current behavior)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        json_object
      </code>
    </td>
    
    <td>
      Forces valid JSON output without schema validation
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        json_schema
      </code>
    </td>
    
    <td>
      Forces JSON output matching the provided schema
    </td>
  </tr>
</tbody>
</table>

### JSON Schema Fields

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        name
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      Identifier for the schema
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        description
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Description of what the schema represents
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        schema
      </code>
    </td>
    
    <td>
      object
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      JSON Schema definition
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        strict
      </code>
    </td>
    
    <td>
      boolean
    </td>
    
    <td>
      No
    </td>
    
    <td>
      Enforce strict schema adherence (default: <code>
        true
      </code>
      
      )
    </td>
  </tr>
</tbody>
</table>

### Supported Schema Features

The following JSON Schema features are supported:

- **Types**: `string`, `number`, `integer`, `boolean`, `array`, `object`, `null`
- **Constraints**: `enum`, `minimum`, `maximum`, `minLength`, `maxLength`, `minItems`, `maxItems`
- **Structure**: `properties`, `required`, `items`, `additionalProperties`
- **Metadata**: `description` (used to guide the model)

### Notes

- Tools (RAG, web search, etc.) work with structured output — the mind can still search its knowledge base before generating the structured response
- The `parsed` field contains the parsed JSON object for convenience; `content` contains the raw JSON string
- All major providers (OpenAI, Anthropic, Google) support structured output
- For complex schemas, consider adding `description` fields to guide the model's output

## Tool Calling

Enable minds to call your custom functions during conversations. This follows the OpenAI-compatible function calling pattern and lets you extend minds' capabilities with external tools and APIs.

### How It Works

1. **Define tools**: Pass tool definitions with names, descriptions, and JSON Schema parameters
2. **Mind decides**: The mind determines when to call your tools based on the conversation (or you force it with `tool_choice`)
3. **API returns tool calls**: The response includes `tool_calls` with the tool name and generated arguments
4. **Execute tools**: You run the tools in your application and get the results
5. **Send results back**: Include tool results in the next message with `role: "tool"`
6. **Mind responds**: The mind incorporates the tool results into its final response

### Basic Example

**Request with tools:**

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "What is the weather in Berlin?"
      }
    ],
    "tools": [
      {
        "name": "get_weather",
        "description": "Get current weather for a city",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {
              "type": "string",
              "description": "City name"
            },
            "units": {
              "type": "string",
              "enum": ["celsius", "fahrenheit"],
              "description": "Temperature units"
            }
          },
          "required": ["city"]
        }
      }
    ]
  }'
```

**Response:**

```json
{
  "content": "",
  "tool_calls": [
    {
      "id": "call_abc123",
      "name": "get_weather",
      "arguments": {
        "city": "Berlin",
        "units": "celsius"
      }
    }
  ]
}
```

**Execute the tool and send results back:**

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "What is the weather in Berlin?"
      },
      {
        "role": "assistant",
        "content": "",
        "tool_calls": [
          {
            "id": "call_abc123",
            "name": "get_weather",
            "arguments": {
              "city": "Berlin",
              "units": "celsius"
            }
          }
        ]
      },
      {
        "role": "tool",
        "tool_call_id": "call_abc123",
        "content": "{\"temperature\": 18, \"condition\": \"partly cloudy\", \"humidity\": 65}"
      }
    ],
    "tools": [
      {
        "name": "get_weather",
        "description": "Get current weather for a city",
        "parameters": {
          "type": "object",
          "properties": {
            "city": { "type": "string" },
            "units": { "type": "string", "enum": ["celsius", "fahrenheit"] }
          },
          "required": ["city"]
        }
      }
    ]
  }'
```

**Final response:**

```json
{
  "content": "The current weather in Berlin is 18°C and partly cloudy, with 65% humidity."
}
```

### Tool Definition Schema

Each tool must follow this structure:

```json
{
  "name": "tool_name",
  "description": "Clear description of when and how to use this tool",
  "parameters": {
    "type": "object",
    "properties": {
      "param1": {
        "type": "string",
        "description": "What this parameter does"
      }
    },
    "required": ["param1"]
  },
  "strict": true
}
```

**Required fields:**

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        name
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      Function name. Must be unique and cannot conflict with internal tools.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        description
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      Clear description of what the tool does and when to use it. This guides the mind's tool selection.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parameters
      </code>
    </td>
    
    <td>
      object
    </td>
    
    <td>
      JSON Schema defining the function arguments.
    </td>
  </tr>
</tbody>
</table>

**Optional fields:**

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        strict
      </code>
    </td>
    
    <td>
      boolean
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Enforce strict schema validation for arguments.
    </td>
  </tr>
</tbody>
</table>

### Tool Choice Modes

Control when and how the mind calls tools using the `tool_choice` parameter:

<table>
<thead>
  <tr>
    <th>
      Value
    </th>
    
    <th>
      Behavior
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        "auto"
      </code>
    </td>
    
    <td>
      Mind decides whether to call tools (default)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        "required"
      </code>
    </td>
    
    <td>
      Mind must call at least one tool before responding
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        "none"
      </code>
    </td>
    
    <td>
      Disable tool calling for this turn
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        {"name": "tool_name"}
      </code>
    </td>
    
    <td>
      Force the mind to call a specific tool
    </td>
  </tr>
</tbody>
</table>

**Examples:**

```json
// Let the mind decide
{
  "messages": [...],
  "tools": [...],
  "tool_choice": "auto"
}

// Force a specific tool
{
  "messages": [...],
  "tools": [...],
  "tool_choice": {
    "name": "search_database"
  }
}

// Require at least one tool call
{
  "messages": [...],
  "tools": [...],
  "tool_choice": "required"
}
```

### Parallel Tool Calls

By default, minds can call multiple tools in a single turn for efficiency:

```json
{
  "content": "",
  "tool_calls": [
    {
      "id": "call_1",
      "name": "get_customer",
      "arguments": { "id": "CUST-001" }
    },
    {
      "id": "call_2",
      "name": "get_customer",
      "arguments": { "id": "CUST-002" }
    }
  ]
}
```

To disable parallel calls and force sequential execution:

```json
{
  "messages": [...],
  "tools": [...],
  "parallel_tool_calls": false
}
```

### Tool Message Format

When sending tool results back, use the `tool` role:

```json
{
  "role": "tool",
  "tool_call_id": "call_abc123",
  "content": "{\"result\": \"success\", \"data\": {...}}"
}
```

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        role
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      Must be <code>
        "tool"
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tool_call_id
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      The <code>
        id
      </code>
      
       from the tool call in the assistant's response
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        content
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <strong>
        Yes
      </strong>
    </td>
    
    <td>
      Tool execution result (typically JSON string)
    </td>
  </tr>
</tbody>
</table>

### Internal vs User Tools

Minds has built-in server-side tools that execute automatically:

<table>
<thead>
  <tr>
    <th>
      Internal Tool
    </th>
    
    <th>
      Purpose
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        GET_SPARK_RAG
      </code>
    </td>
    
    <td>
      Search the mind's knowledge base
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        WEB_SEARCH
      </code>
    </td>
    
    <td>
      Search the web
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        GENERATE_IMAGE
      </code>
    </td>
    
    <td>
      Generate images with AI
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        DISPLAY_IMAGE
      </code>
    </td>
    
    <td>
      Display images from the mind's memory
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        DOCUMENT_PROCESSING
      </code>
    </td>
    
    <td>
      Analyze uploaded files
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ANALYZE_LINK
      </code>
    </td>
    
    <td>
      Fetch and analyze web URLs
    </td>
  </tr>
</tbody>
</table>

**Key differences:**

- **Internal tools**: Execute server-side, results included in `content` and `metadata`. Never returned in `tool_calls`.
- **User tools**: Returned in `tool_calls` for you to execute. Results must be sent back as `tool` messages.

You cannot override or disable internal tools. User tools are **additive** — they extend the mind's capabilities.

### Complete Multi-Tool Example

A legal assistant mind with multiple custom tools:

```bash
curl -X POST "https://getminds.ai/api/v1/minds/mind-id/completion" \
  -H "Authorization: Bearer minds_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "Create a new case for Schmidt vs. Mueller and search for similar precedents"
      }
    ],
    "tools": [
      {
        "name": "create_case",
        "description": "Create a new legal case in the system",
        "parameters": {
          "type": "object",
          "properties": {
            "title": {
              "type": "string",
              "description": "Case title (parties involved)"
            },
            "practice_area": {
              "type": "string",
              "enum": ["corporate", "litigation", "employment", "ip"],
              "description": "Legal practice area"
            },
            "client_id": {
              "type": "string",
              "description": "Client identifier"
            }
          },
          "required": ["title", "practice_area"]
        }
      },
      {
        "name": "search_precedents",
        "description": "Search legal database for similar cases",
        "parameters": {
          "type": "object",
          "properties": {
            "keywords": {
              "type": "array",
              "items": { "type": "string" },
              "description": "Search keywords"
            },
            "practice_area": {
              "type": "string",
              "description": "Filter by practice area"
            },
            "max_results": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Maximum number of results"
            }
          },
          "required": ["keywords"]
        }
      }
    ],
    "parallel_tool_calls": true
  }'
```

**Response with parallel tool calls:**

```json
{
  "content": "",
  "tool_calls": [
    {
      "id": "call_1",
      "name": "create_case",
      "arguments": {
        "title": "Schmidt vs. Mueller",
        "practice_area": "litigation"
      }
    },
    {
      "id": "call_2",
      "name": "search_precedents",
      "arguments": {
        "keywords": ["Schmidt", "Mueller"],
        "practice_area": "litigation",
        "max_results": 10
      }
    }
  ]
}
```

### Best Practices

1. **Write clear descriptions**: The `description` field is critical. Be specific about when and why to use each tool.```json
❌ "description": "Search database"
✅ "description": "Search the legal precedents database for similar cases based on keywords and practice area"
```
2. **Use parameter descriptions**: Help the mind understand what each parameter does.```json
"case_id": {
  "type": "string",
  "description": "Unique case identifier in format CASE-YYYY-NNNN"
}
```
3. **Leverage enums for constrained values**:```json
"status": {
  "type": "string",
  "enum": ["pending", "active", "closed", "archived"]
}
```
4. **Set validation constraints**:```json
"priority": {
  "type": "integer",
  "minimum": 1,
  "maximum": 5,
  "description": "Priority level (1=lowest, 5=highest)"
}
```
5. **Enable strict mode**: Keep `strict: true` (default) to ensure the mind generates valid arguments.
6. **Return structured tool results**: Use JSON for tool results to make them easy to parse:```json
{
  "role": "tool",
  "tool_call_id": "call_123",
  "content": "{\"success\": true, \"case_id\": \"CASE-2026-001\", \"created_at\": \"2026-03-30T23:00:00Z\"}"
}
```
7. **Handle errors gracefully**: Return error details in the tool result:```json
{
  "role": "tool",
  "tool_call_id": "call_123",
  "content": "{\"success\": false, \"error\": \"Case already exists\", \"error_code\": \"DUPLICATE_CASE\"}"
}
```

### Limitations

- **Maximum 128 tools** per request
- Tool names must be unique and cannot conflict with internal tool names
- Tool execution happens client-side — you are responsible for running and securing your tools
- Tool results must be sent back in the conversation history for the mind to respond

### JSON Schema Support

The `parameters` field supports standard JSON Schema features:

**Types:**

- `string`, `number`, `integer`, `boolean`, `array`, `object`, `null`

**Validation:**

- `enum` — Restrict to specific values
- `minimum`, `maximum` — Numeric bounds
- `minLength`, `maxLength` — String length
- `minItems`, `maxItems` — Array size
- `pattern` — Regex validation
- `format` — String formats (e.g., `"date-time"`, `"email"`, `"uri"`)

**Structure:**

- `properties` — Object properties
- `required` — Required fields
- `items` — Array item schema
- `additionalProperties` — Allow/disallow extra properties

**Example with advanced validation:**

```json
{
  "name": "schedule_meeting",
  "description": "Schedule a meeting with a client",
  "parameters": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "minLength": 1,
        "maxLength": 200
      },
      "date": {
        "type": "string",
        "format": "date-time",
        "description": "Meeting date and time in ISO 8601 format"
      },
      "attendees": {
        "type": "array",
        "items": {
          "type": "string",
          "format": "email"
        },
        "minItems": 1,
        "maxItems": 20
      },
      "duration_minutes": {
        "type": "integer",
        "minimum": 15,
        "maximum": 480,
        "description": "Meeting duration (15-480 minutes)"
      }
    },
    "required": ["title", "date", "attendees"]
  }
}
```

## How It Works

### 1. Context Loading

When you send a message, the mind:

- Loads its system prompt and configuration
- **Automatically searches its knowledge base** for relevant information
- Considers the conversation history

### 2. Processing

The mind:

- Analyzes your message in context
- **Grounds responses in retrieved knowledge** with citations
- Accesses additional tools (web search, image generation, etc.) if needed
- Formulates a response aligned with its personality

### 3. Response Generation

The mind:

- Generates a response that reflects its expertise
- **Includes citations** when using knowledge base or web sources
- Returns the message with optional metadata (citations, images, etc.)

## Metadata

Responses can include additional metadata:

### Images

When a mind generates or displays images:

```json
{
  "content": "Here are some logo concepts...",
  "metadata": {
    "images": [
      {
        "id": "img_123",
        "url": "https://...",
        "filename": "Logo Concept 1",
        "description": "Modern minimalist logo with blue gradient",
        "source": "generated"
      }
    ]
  }
}
```

### Knowledge Citations

When a mind retrieves information from its knowledge base or web search:

```json
{
  "content": "Based on recent research, solar panel efficiency has improved significantly...",
  "metadata": {
    "ragCitations": [
      {
        "id": "9bf44ab0-9d83-42ec-b941-c0ab7610e949",
        "displaySource": "Mind knowledge",
        "similarity": 0.85
      },
      {
        "id": "external-web-123",
        "displaySource": "https://example.com/solar-research",
        "similarity": 0.92
      }
    ]
  }
}
```

**Citation Fields:**

- `id` - Unique identifier for the source
- `displaySource` - Human-readable source name or URL
- `similarity` - Relevance score (0-1) indicating how well the source matches the query

Minds automatically search their knowledge base before responding and include citations when grounding their answers in specific sources.

## Access Control

You can chat with Minds you:

- **Own** - Minds you created
- **Collaborate on** - Minds shared with you directly (you were added as a member)
- **Share through your team** - Minds shared with a team you belong to
- **Reach through an Audience** - Minds inside an Audience you own, belong to, or that is shared with your team, even when the Minds themselves are not shared individually
- **Reach through a Study** - Minds inside a Study you belong to
- **Public minds** - Publicly accessible minds

Audience and Study access is read-and-chat only; it never grants edit or delete rights on the Mind. Use `GET /api/v1/minds/library` to see every Mind you can chat with.

Attempting to access unauthorized minds returns:

```json
{
  "statusCode": 403,
  "statusMessage": "Access denied"
}
```

## Response Formats

### Text Response

Most responses are plain text:

```json
{
  "content": "Based on current trends, I recommend focusing on..."
}
```

### Structured Response

Some minds may return structured content:

```json
{
  "content": "Here's my analysis:\n\n1. Trend: AI Personalization\n   - Impact: High\n   - Timeline: 6-12 months\n\n2. Trend: Short-form Video\n   - Impact: Very High\n   - Timeline: Immediate"
}
```

### Empty Response with Metadata

Sometimes only metadata is returned (e.g., for image generation):

```json
{
  "content": "",
  "metadata": {
    "images": [...]
  }
}
```

## Best Practices

### Be Specific

```text
❌ "Tell me about marketing"
✅ "What are the most cost-effective digital marketing channels for a B2B SaaS startup with a $5K monthly budget?"
```

### Provide Context

```text
✅ "We're launching a sustainable fashion brand targeting Gen Z. What social media strategy would you recommend?"
```

### Use Follow-ups

Take advantage of conversation memory:

```text
User: "What are the top trends?"
Assistant: "The top trends are..."
User: "Which of these would work best for a small budget?"
Assistant: "For a small budget, I'd focus on..."
```

### Reference Knowledge

If you've uploaded knowledge, reference it:

```text
✅ "Based on our brand guidelines, what tone should we use for this campaign?"
```

## Error Responses

### 400 Bad Request

Missing or invalid Mind ID:

```json
{
  "statusCode": 400,
  "statusMessage": "Mind ID is required"
}
```

Unsupported provider:

```json
{
  "statusCode": 400,
  "statusMessage": "Unsupported provider: 'invalid'. Supported providers: openai, anthropic, google."
}
```

Ambiguous model name without provider:

```json
{
  "statusCode": 400,
  "statusMessage": "Cannot auto-detect provider for model 'my-model'. Please specify a 'provider' parameter (openai, anthropic, or google)."
}
```

### 401 Unauthorized

Invalid API key.

### 403 Forbidden

Access denied to Mind:

```json
{
  "statusCode": 403,
  "statusMessage": "Access denied"
}
```

### 404 Not Found

Mind doesn't exist:

```json
{
  "statusCode": 404,
  "statusMessage": "Mind not found"
}
```

## Usage Notes

- The v1 API enforces a configurable per-account rate limit (300 requests per minute by default)
- Read `RateLimit-Limit` and `RateLimit-Remaining`, and honor `Retry-After` after `429`
- Keep parallel completions bounded because generation requests are resource-intensive

## Next Steps

- Understand [latency and performance](/docs/api/latency)
- Learn about [errors and rate limits](/docs/api/errors)
- Create your first [mind](/docs/api/minds)
- Upload [knowledge](/docs/api/knowledge) to enhance responses
- Read the [API overview](/docs/api/overview)
