Conversations
On this page
Conversations, called rooms in the API, store chat history on the data plane so a client can reload it. The Mortar console uses them for its sidebar; you can use them to keep a transcript next to the model that produced it.
Conversations are owned by whoever creates them. Those created with an API key belong to the key's organization and are visible to every key in it; those created in the console belong to the signed-in person.
Conversations are kept in the memory of the data-plane replica and are cleared when it restarts. Each owner can keep 200 conversations and each conversation keeps its latest 1,000 messages. Keep your own copy of anything you can't lose.
The conversation object
| Field | Type | Description |
|---|---|---|
id |
string | room- followed by 8 hexadecimal characters. |
headerTitle |
string | The title shown above the conversation. |
headerSubtitle |
string | The line under the title, such as the model and environment. |
sidebarTitle |
string | The title shown in a list of conversations. |
sidebarSubtitle |
string | A preview of the latest message, up to 80 characters. |
meta |
string | A short label for when the conversation last changed, such as Now. |
badge |
object | Optional. A label with type and label. |
hasEnded |
boolean | Whether the conversation was marked as ended. |
The message object
| Field | Type | Description |
|---|---|---|
id |
string | The message ID. |
type |
string | message for anything added through the API. |
roomId |
string | The conversation it belongs to. |
senderId |
string | Who sent it, such as you or mortar. |
senderName |
string | The sender's display name. |
content |
string | The message text. |
timestamp |
string | When it was sent, as an ISO 8601 time in UTC. |
reactions |
object | Emoji reactions: each key is an emoji and its value lists who reacted. |
attachments |
array | Files shown with the message, each with id, name and meta. |
isDeleted |
boolean | Whether the message was deleted. |
isSelected |
boolean | Whether the message is selected in the console. |
replyTo |
string or null | The ID of the message this one answers. |
requestId |
string | Only on a message saved with one: the id of the chat completion it is the reply from. |
usage |
object | Only on a message saved with a requestId: what that completion was billed, attached by Mortar. See the usage object. |
The usage object
What a reply's completion was billed: Mortar's own settlement of the request, the figures the cost.update telemetry event reports. Mortar attaches it to the message that names the completion in requestId; a usage you send is ignored. A completion's usage waits 30 minutes for its message, and a message as long for its completion, so you can save a stopped reply at once and its usage follows when the stream has closed. A message saved without a requestId, or later than that, has no usage. Amounts are US dollars at sample pricing, sent to 12 significant digits.
| Field | Type | Description |
|---|---|---|
requestId |
string | The completion's id. |
model |
string | The display name of the model that answered. |
modelId |
string | The model's ID, as the request named it. |
finishReason |
string | stop, length, tool_calls or the model server's own reason; stopped when the reply was stopped or its client left; error when the model server failed after the reply had begun. |
usageSource |
string | upstream when the counts are the model server's own, estimate when Mortar counted them. |
promptTokens |
integer | Tokens in the prompt. |
completionTokens |
integer | Tokens in the reply. |
cacheReadTokens |
integer | Prompt tokens read from the prefix cache. |
cacheWriteTokens |
integer | Prompt tokens prefilled and written to the cache. |
inputUsd |
number | The prompt's cost, cache reads and writes included. |
outputUsd |
number | The reply's cost. |
totalUsd |
number | inputUsd plus outputUsd. |
baselineUsd |
number | What the same request costs with no prefix cache. |
savedUsd |
number | baselineUsd minus totalUsd. Negative on a turn that only wrote the cache. |
ttftMs |
integer | Milliseconds to the first token: measured when a model server answered, Mortar's simulated figure otherwise. |
durationMs |
integer | Milliseconds from Mortar receiving the request to the reply's end. |
List conversations
/v1/rooms
Lists your conversations, oldest first. Needs an API key.
curl https://api.mortar.one/v1/rooms \
-H "Authorization: Bearer $MORTAR_API_KEY"{
"object": "list",
"data": [
{
"id": "room-9a8b7c6d",
"headerTitle": "Capacity planning",
"headerSubtitle": "Qwen 2.5 7B Instruct · Managed · ap-south-1",
"sidebarTitle": "Capacity planning",
"sidebarSubtitle": "Which GPU should I run a 32B model on?",
"meta": "Now",
"hasEnded": false
}
]
}Create a conversation
/v1/rooms
Starts an empty conversation. Needs an API key.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
title |
string | No | The conversation's title. Defaults to New conversation. |
subtitle |
string | No | The line under the title. Defaults to the model and environment this deployment serves. |
Request headers
| Header | Required | Description |
|---|---|---|
X-Mortar-Session |
No | A telemetry session to notify. Mortar publishes room.created, room.updated and room.deleted events to that session's stream, which only your organization can follow. |
Example
curl https://api.mortar.one/v1/rooms \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Release notes"}'{
"id": "room-3fa85f64",
"headerTitle": "Release notes",
"headerSubtitle": "Qwen 2.5 7B Instruct · Managed · ap-south-1",
"sidebarTitle": "Release notes",
"sidebarSubtitle": "No messages yet",
"meta": "Now",
"hasEnded": false
}The response status is 201. With 200 conversations already saved, the request fails with 409 and the code room_limit_reached; delete one to make room.
Add a message
/v1/rooms/{id}/messages
Saves a message to a conversation and makes its text the conversation's preview. Mortar stores the message as you send it; it doesn't generate a reply. Needs an API key.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The conversation's ID. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
content |
string | Yes | The message text. |
id |
string | No | Your own ID for the message. Defaults to msg- and 8 random hexadecimal characters. |
senderId |
string | No | Who sent it. Defaults to you. |
senderName |
string | No | The sender's display name. Defaults to You. |
timestamp |
string | No | When it was sent. Defaults to now, as an ISO 8601 time in UTC. |
reactions |
object | No | Emoji reactions, keyed by emoji. |
attachments |
array | No | Files to show with the message, each with id, name and meta. |
replyTo |
string | No | The ID of the message this one answers. |
requestId |
string | No | The id of the chat completion this message is the reply from. Mortar attaches what that completion was billed as usage. |
Example
curl https://api.mortar.one/v1/rooms/room-3fa85f64/messages \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Summarise the changes from this week."}'{
"id": "msg-7d1c2b9e",
"type": "message",
"roomId": "room-3fa85f64",
"senderId": "you",
"senderName": "You",
"content": "Summarise the changes from this week.",
"timestamp": "2026-10-29T09:30:00.000Z",
"reactions": {},
"attachments": [],
"isDeleted": false,
"isSelected": false,
"replyTo": null
}The response status is 201.
Save a reply with its usage
Name the completion a reply came from, and the saved message carries what it was billed.
curl https://api.mortar.one/v1/chat/completions \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"stream": false, "max_tokens": 200, "messages": [{"role": "user", "content": "What does max_tokens limit?"}]}'{
"id": "chatcmpl-5d8e1f4a7b0c3e6d9a2b5c8f",
"object": "chat.completion",
"created": 1767225600,
"model": "Qwen/Qwen2.5-7B-Instruct",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "It caps how many tokens the model may generate for this reply."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 32,
"completion_tokens": 13,
"total_tokens": 45
}
}curl https://api.mortar.one/v1/rooms/room-3fa85f64/messages \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"senderId": "mortar", "senderName": "Qwen 2.5 7B Instruct", "content": "It caps how many tokens the model may generate for this reply.", "requestId": "chatcmpl-5d8e1f4a7b0c3e6d9a2b5c8f"}'{
"id": "msg-2e4a6c8b",
"type": "message",
"roomId": "room-3fa85f64",
"senderId": "mortar",
"senderName": "Qwen 2.5 7B Instruct",
"content": "It caps how many tokens the model may generate for this reply.",
"timestamp": "2026-10-29T09:30:05.000Z",
"reactions": {},
"attachments": [],
"isDeleted": false,
"isSelected": false,
"replyTo": null,
"requestId": "chatcmpl-5d8e1f4a7b0c3e6d9a2b5c8f",
"usage": {
"requestId": "chatcmpl-5d8e1f4a7b0c3e6d9a2b5c8f",
"model": "Qwen 2.5 7B Instruct",
"modelId": "Qwen/Qwen2.5-7B-Instruct",
"finishReason": "stop",
"usageSource": "estimate",
"promptTokens": 32,
"completionTokens": 13,
"cacheReadTokens": 0,
"cacheWriteTokens": 32,
"inputUsd": 0.000001252,
"outputUsd": 0.0000030849,
"totalUsd": 0.0000043369,
"baselineUsd": 0.0000040865,
"savedUsd": -0.0000002504,
"ttftMs": 140,
"durationMs": 152
}
}The figures are those of the completion's cost.update event. Its first turn wrote its prompt to the cache, so savedUsd is negative.
List messages
/v1/rooms/{id}/messages
Pages backwards through a conversation: each page holds the newest messages before a point, in the order they were sent. Needs an API key.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The conversation's ID. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
limit |
integer | How many messages to return, up to 200. Defaults to 50. |
before |
string | A message ID. Returns the messages sent before it. Leave it out for the newest page. |
Example
curl "https://api.mortar.one/v1/rooms/room-3fa85f64/messages?limit=20" \
-H "Authorization: Bearer $MORTAR_API_KEY"{
"object": "list",
"data": [
{
"id": "msg-7d1c2b9e",
"type": "message",
"roomId": "room-3fa85f64",
"senderId": "you",
"senderName": "You",
"content": "Summarise the changes from this week.",
"timestamp": "2026-10-29T09:30:00.000Z",
"reactions": {},
"attachments": [],
"isDeleted": false,
"isSelected": false,
"replyTo": null
}
],
"hasMore": false
}Response
| Field | Type | Description |
|---|---|---|
object |
string | Always list. |
data |
array | Message objects, oldest first. Empty when the conversation has no messages, or none before before. |
hasMore |
boolean | Whether older messages exist. Pass the first message's id as before to fetch them. |
Update a conversation
/v1/rooms/{id}
Renames a conversation or marks it as ended. Fields you leave out are unchanged. Needs an API key.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The conversation's ID. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
title |
string | No | A new title. An empty title leaves the old one. |
hasEnded |
boolean | No | true to mark the conversation as ended, false to reopen it. |
Example
curl -X PATCH https://api.mortar.one/v1/rooms/room-3fa85f64 \
-H "Authorization: Bearer $MORTAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Release notes, week 44", "hasEnded": true}'{
"id": "room-3fa85f64",
"headerTitle": "Release notes, week 44",
"headerSubtitle": "Qwen 2.5 7B Instruct · Managed · ap-south-1",
"sidebarTitle": "Release notes, week 44",
"sidebarSubtitle": "Summarise the changes from this week.",
"meta": "Now",
"hasEnded": true
}Delete a conversation
/v1/rooms/{id}
Deletes a conversation and all of its messages. This can't be undone. Needs an API key.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The conversation's ID. |
Example
curl -X DELETE https://api.mortar.one/v1/rooms/room-3fa85f64 \
-H "Authorization: Bearer $MORTAR_API_KEY"{
"deleted": true,
"id": "room-3fa85f64"
}Errors
| Status | Code | When |
|---|---|---|
| 404 | not_found |
No conversation with that ID belongs to you. |
| 409 | room_limit_reached |
You already have 200 conversations. |
| 400 | The body isn't valid JSON. |