Messages API
Realtime chat channels that hang off a live Meeting. Every Meeting starts with one default thread (main) and - just like a Slack channel - any client can spin up extra threads on‑the‑fly (/v1/meetings/{meeting_id}/threads). Use them to separate side‑bars (qa‑chat), action‑items, or Assistant‑only command lanes.
Looking for auth, base URLs, pagination, or error formats? Head over to API Foundations.
Endpoints at a glance
| Method & Path | Purpose |
|---|---|
GET /v1/meetings/{meeting_id}/threads/{id}/messages | List messages (cursor‑paginated) |
POST /v1/meetings/{meeting_id}/threads/{id}/messages | Post a user chat message / inline tool call |
GET /v1/meetings/{meeting_id}/threads/{id}/stream | Stream live messages (SSE, WebSocket upgrade) |
Real‑world hook: Daily Scrum Assistant auto‑flags new blockers in the blockers thread while the team is still in the stand‑up.
Message object schema
| Field | Type | Description |
|---|---|---|
id | string | Identifier (prefix msg_). |
thread_id | string | Owning thread. |
created_at | timestamp | ISO‑8601 UTC. |
role | string | user, assistant, system, transcript_segment, tool_call_started, tool_call_finished. |
type | string | answer (default) tool_suggestion or tool_response. |
content | string|object | Message text or tool payload/result JSON. |
segment_offset | integer? | Milliseconds offset inside the meeting for transcript segments. |
tool_name | string? | Populated for tool call rows. |
tool_params | object? | Arguments passed to the tool. |
tool_result | object? | Result blob once tool_call_finished arrives. |
Pagination follows the shared cursor model (cursor, limit, has_more). Newest‑first ordering by default; set order=asc to replay chronologically.
List messages
GET /v1/meetings/{meeting_id}/threads/{id}/messages
Query params
| Name | Type | Default | Description |
|---|---|---|---|
cursor | string? | – | Pointer from previous page. |
limit | integer? | 50 | 1–200 messages per page. |
order | string? | desc | asc or desc. |
Post a message / inline tool call
POST /v1/meetings/{meeting_id}/threads/{id}/messages
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
role | string | yes | user only - assistant/system messages are server‑generated. |
content | string | yes* | Natural‑language prompt. If it requests an action, the platform automatically infers and executes the proper tool. |
🛠️ Tool call flow: Simply phrase the request (e.g. "Post 🚨 New blocker: login API 500s to #general on Slack"). The Assistant will reply with a
tool_suggestion. Confirm by postingconfirmToolUse: trueto execute the action, orfalseto decline.
Example – ask a question
curl -X POST https://api.voilo.io/meetings/meeting_123/threads/th_abc/messages \
-H "Authorization: Bearer $VOILO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "user",
"content": "Summarize the last 30 seconds"
}'
Execution Flow for Tool Calls
When a user request may require running an external tool (Slack, Jira, calendar, etc.) the exchange now follows the five‑step handshake below:
To enable the tool, you need to configure it and the assistant. See Tool Calling for more details.
- User request - The client posts a normal chat message to
POST /v1/meetings/{meeting_id}/threads/{id}/messages. No special fields are needed to ask for the action.
curl -X POST https://api.voilo.io/meetings/meeting_123/threads/th_abc/messages \
-H "Authorization: Bearer $VOILO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "user",
"content": "Post 🚨 New blocker: login API 500s to #general on Slack"
}'
- Assistant suggestion - If the Assistant decides the request should be handled by a tool, it replies with a message whose
typeis"tool_suggestion". The payload includestool_nameandtool_params.
{
"type": "tool_suggestion",
"tool_name": "slack_post_message",
"tool_description": "Post a message to a Slack channel",
"tool_params": {
"channel": "general",
"text": "🚨 New blocker: login API 500s"
},
"expected_outcome": "The message is posted to the Slack channel",
"tool_calls": [
{
"name": "slack_post_message",
"args": {
"channel": "general",
"text": "🚨 New blocker: login API 500s"
},
"type": "tool_call",
"id": "call_123"
}
]
}
- Client decision - Your UI (or server logic) chooses whether to execute the suggested tool. You can surface the details to the end‑user or auto‑approve.
- Confirmation - Post a follow‑up chat message in the same thread containing the top‑level field
"confirmToolUse": true(orfalse).
curl -X POST https://api.voilo.io/meetings/meeting_123/threads/th_abc/messages \
-H "Authorization: Bearer $VOILO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "user",
"content": "",
"confirmToolUse": true
}'
- Tool execution - When
confirmToolUseistruethe platform runs the tool and streams back atype = "tool_response"message carrying the result intool_result.
{
"type": "tool_response",
"answer": "The message is posted to the Slack channel",
"tool_results": [{
"tool": "slack_post_message",
"args": {
"channel": "general",
"text": "🚨 New blocker: login API 500s"
},
"result": "The message is posted to the Slack channel"
}]
}
Stream live messages
GET /v1/meetings/{meeting_id}/threads/{id}/stream
The server only supports WebSocket for realtime delivery. Include the typical handshake headers (Connection: Upgrade, Upgrade: websocket) plus any subprotocol you need.
- Each inbound text frame is a JSON‑encoded Message delivered the moment it is created.
- Heartbeat ping frames are emitted every 30 seconds; respond with pong (most WS libraries do this automatically).
// sample text frame payload
{
"thread_id": "th_blockers",
"created_at": "2025-06-17T11:50:03Z",
"role": "user",
"content": "List all blockers",
"segment_offset": 271200
}
See also
- Assistant Configuration – how to wire prompts & tools.
- API Foundations – base URLs, auth, pagination, and errors.
- Threads API – how to create threads.
- Tool Calling – how to enable tools.