1. Threads
  2. Add Message to Thread (Legacy)
POST
/threads/{thread_id}/messages
curl --request POST \
     --url https://app.backboard.io/api/threads/{thread_id}/messages \
     --header 'X-API-Key: <api-key>' \
     --header 'authorization: <authorization>' \
     --header 'x_session_token: <x_session_token>' \
     --header 'Content-Type: application/json' \
     --data '{
  "content": "string",
  "llm_provider": "string",
  "model_name": "string",
  "system_prompt": "string",
  "image_generation": "off",
  "image_model_provider": "string",
  "image_model_name": "string",
  "stream": false,
  "thinking": {
    "effort": "low",
    "budget_tokens": 0,
    "max_tokens": 1,
    "exclude_reasoning": true
  },
  "tools": [
    {}
  ],
  "memory": "off",
  "memory_response_citation": false,
  "memory_citation": false,
  "memory_pro": "string",
  "web_search": "off",
  "send_to_llm": "true",
  "json_output": false,
  "custom_timestamp": "<date-time>",
  "metadata": "string",
  "voice": {},
  "video_generation": "off",
  "video_model_provider": "string",
  "video_model_name": "string",
  "video_config": {
    "duration": 1,
    "resolution": "string",
    "aspect_ratio": "string",
    "size": "string",
    "generate_audio": true,
    "seed": 1,
    "provider": {},
    "upscale_factor": 0,
    "creativity": 1
  },
  "image_config": {
    "resolution": "string",
    "aspect_ratio": "string",
    "size": "string",
    "quality": "string",
    "background": "string",
    "output_format": "string",
    "output_compression": 0,
    "n": 1,
    "seed": 1,
    "provider": {}
  },
  "system_one": {
    "questions": {
      "additionalProperty": {
        "instructions": "string",
        "type": "string",
        "criteria": {
          "true": "string",
          "false": "string"
        }
      }
    },
    "state": "string"
  }
}'

​
Overview

Add a new message to an existing thread. You can include text content and optionally attach files to the message for document-based context.

memory_response_citation is optional and defaults to false. Set it to true when you want memory-backed replies to explicitly cite retrieved memories in the assistant’s text response. retrieved_memories is still returned independently.

json_output is optional and defaults to false. Set it to true to request JSON object output from the model. The model will return a valid JSON object instead of free-form text. This is automatically ignored when RAG (documents), web search, or custom tools are active on the message. Not all models support this — use the Models API with supports_json_output=true to find compatible models.

​
File Attachments

This legacy route shares the canonical message endpoint’s image/video configuration and validation. Use image_config or video_config with the corresponding generation mode enabled; send objects in JSON or JSON-encoded strings in multipart form fields. Both streaming and non-streaming use the same controls. Prefer Send Message for new integrations.

You can attach files to messages to provide additional context or documents for the assistant to reference. The API supports attaching files in two ways:

  1. Using file IDs - Reference previously uploaded files
  2. Direct file upload - Upload files directly with the message (multipart/form-data)

​
Code Examples

​
Basic Message (No Attachments)

import requests

url = "https://app.backboard.io/api/threads/thread_abc123/messages"
headers = {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

data = {
    "content": "Can you analyze the quarterly report?",
    "role": "user"
}

response = requests.post(url, headers=headers, json=data)
print(response.json())

​
Message with File Upload (Multipart)

import requests

url = "https://app.backboard.io/api/threads/thread_abc123/messages"
headers = {
    "X-API-Key": "YOUR_API_KEY"
}

# Open the file in binary mode
with open('quarterly_report.pdf', 'rb') as file:
    files = {
        'files': ('quarterly_report.pdf', file, 'application/pdf')
    }

    data = {
        'content': 'Please analyze this quarterly report and summarize key metrics',
        'role': 'user'
    }

    response = requests.post(url, headers=headers, data=data, files=files)
    print(response.json())

​
Message with Multiple Files

import requests

url = "https://app.backboard.io/api/threads/thread_abc123/messages"
headers = {
    "X-API-Key": "YOUR_API_KEY"
}

files = [
    ('files', ('report_q1.pdf', open('report_q1.pdf', 'rb'), 'application/pdf')),
    ('files', ('report_q2.pdf', open('report_q2.pdf', 'rb'), 'application/pdf')),
    ('files', ('summary.xlsx', open('summary.xlsx', 'rb'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'))
]

data = {
    'content': 'Compare these quarterly reports and analyze the trends',
    'role': 'user'
}

response = requests.post(url, headers=headers, data=data, files=files)

# Close files
for _, file_tuple in files:
    file_tuple[1].close()

print(response.json())

​
Message with File References (Using File IDs)

import requests

url = "https://app.backboard.io/api/threads/thread_abc123/messages"
headers = {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

data = {
    "content": "Review the documents I previously uploaded",
    "role": "user",
    "attachments": [
        {
            "file_id": "file_xyz789",
            "tools": [{"type": "file_search"}]
        },
        {
            "file_id": "file_abc456",
            "tools": [{"type": "file_search"}]
        }
    ]
}

response = requests.post(url, headers=headers, json=data)
print(response.json())

​
File Size and Type Limits

Upload limits apply. Image and video inputs must also meet the selected model’s requirements. Maximum files per message: 10 files Supported formats: PDF, DOCX, TXT, MD, CSV, XLSX, JSON, and more

​
Response

The API returns the created message with attachment metadata:

{
  "id": "msg_abc123",
  "object": "thread.message",
  "created_at": 1699061776,
  "thread_id": "thread_abc123",
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": {
        "value": "Please analyze this quarterly report and summarize key metrics",
        "annotations": []
      }
    }
  ],
  "attachments": [
    {
      "file_id": "file_xyz789",
      "filename": "quarterly_report.pdf",
      "size": 1048576,
      "tools": [{"type": "file_search"}]
    }
  ]
}

​
Authorizations

X-API-Key
required
string
API Key authentication

​
Query Parameters

thread_id
required
string
authorization
x_session_token

​
Body

application/json
content
string

Text content of the message

llm_provider
string

LLM provider name. Default: openai.

model_name
string

Model name. Default: gpt-4o.

system_prompt
string

Per-run system prompt override. Not persisted on the assistant.

image_generation
string

Image generation: 'auto' enables the generate_image tool (requires image_model_provider and image_model_name); 'off' disables it.

image_model_provider
string

Required when image_generation=auto. Provider for generate_image (e.g. openrouter). Ignored when image_generation=off.

image_model_name
string

Required when image_generation=auto. Model for generate_image (e.g. google/gemini-2.5-flash-image). Ignored when image_generation=off.

stream
boolean

Whether to stream the AI response.

thinking
object

Flat reasoning controls inferred from the selected llm_provider/model. Use {} to enable provider defaults, or send only the fields supported by the selected model.

tools
array

Optional per-message tool override (OpenAI-style). Not persisted on the assistant.

memory
string

Memory Lite mode (no reranking): 'Auto', 'Readonly', or 'off'. Cannot be used together with memory_pro.

memory_response_citation
boolean

Whether the assistant should cite retrieved memories in its response text.

memory_citation
boolean

Deprecated alias for memory_response_citation.

memory_pro
string

Memory Pro mode (with reranking, higher cost): 'Auto', 'Readonly', or omit. Cannot be used together with memory.

web_search
string

Web search mode: 'Auto' or 'off'.

send_to_llm
string

Whether to send to LLM for a response.

json_output
boolean

When true, request JSON object output from the model. Ignored when RAG, web search, or custom tools are active.

custom_timestamp
string

Custom timestamp for the message (merged into metadata when stored).

metadata
string

Optional metadata as JSON string.

voice
object

Optional voice config object. Add stt to enable speech-to-text, add tts to enable text-to-speech.

video_generation
string
video_model_provider
string

Required when video_generation=auto; openrouter is supported.

video_model_name
string

Video model ID from /models/video/all.

video_config
object

VideoConfig

image_config
object

ImageConfig

system_one
object

SystemOneConfig

​
Response

application/json
  • 200

  • 422

Successful Response

message
required
string

Message

thread_id
required
string

Thread Id

timestamp
required
string

Timestamp

assistant_id
string | null

Assistant Id

content
string | null

Content

message_id
string | null

Message Id

role
string | null
status
string | null
tool_calls
array | null

Tool Calls

run_id
string | null

Run Id

memory_operation_id
string | null

Memory Operation Id

retrieved_memories
array | null
retrieved_files
array | null

Retrieved Files

retrieved_files_count
integer

Retrieved Files Count

reasoning
string | null

Reasoning

model_provider
string | null

Model Provider

model_name
string | null

Model Name

input_tokens
integer | null

Input Tokens

output_tokens
integer | null

Output Tokens

total_tokens
integer | null

Total Tokens

created_at
string | null

Created At

attachments
array | null
generated_media
array | null
voice_records
object | null

STT/TTS outcome: stt (transcript, input audio_url, usage) and/or tts (output audio_url, usage).

context_usage
object | null

Context Usage

system_one
object | null