Messages

Messages

Reference article: Part of the API reference.

Every workstream has a room: the chat that its people and the agent share. These endpoints read the room's history, post into it, reply in threads, and edit what your key posted. Use them to bring updates from your own systems, such as build results, alerts, or form submissions, to where the team is already talking.

A message posted through the API appears as the key, under the key's name, never as a person or as the agent. Everyone in the room sees it live, as they would a teammate's message. To ask the agent a question and get its answer back, use the agent endpoints instead.

You can only reach rooms of workstreams the key can reach. See Which workstreams a key can reach.

The Message object

{
  "id": "9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64",
  "object": "message",
  "workstream": "3f6c2a1e-8b4d-4e2f-9a7c-5d1b0e6f2a94",
  "text": "Nightly build **passed** on `main` (build 8812).",
  "author": {
    "type": "api_key",
    "id": "key_7fQ2mN4pR8sT1vW3xY5zA1bC",
    "name": "CI status bot"
  },
  "reply_to": null,
  "edited": false,
  "created": 1758792310,
  "updated": null
}
Field Type Description
id string The message's ID, a UUID.
object string Always message.
workstream string The ID of the workstream whose room it's in.
text string or null The message, in Markdown.
author object Who posted it. See Authors.
reply_to string or null The ID of the message this replies to, if it's in a thread.
edited boolean true if the text was changed after posting.
created integer When it was posted, in Unix seconds.
updated integer or null When it was last changed, in Unix seconds.

Authors {#authors}

author.type says what kind of participant posted the message:

Type Posted by author.id author.name
user A person in the app. Their user ID. Their display name.
agent The workstream agent. The ID of the person it was answering. Agent
api_key An API key. The key's ID (key_…). The key's name.
app A Nimbus App. The App's ID. Its display name.
system Nimbus itself. An internal ID. Varies, or null.

author.name can be null when no display name is known. Branch on author.type, and keep a fallback for types you don't recognize: new ones can be added without a new API version.

List messages

Returns messages in the workstream's room, newest first. Each next_cursor takes you further back in history. Deleted messages are left out.

GET /v1/workstreams/{workstream}/messages

Scope: messages:read

Parameter In Type Description
workstream path string The workstream's id or slug.
limit query integer, optional How many messages to return, 1–100. Default 20.
cursor query string, optional The next_cursor from the previous page. See Pagination.

::: code-group

curl "https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages?limit=50" \
  -H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages?limit=50', {
  headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const { data: messages, next_cursor } = await response.json()
response = requests.get(
    "https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages",
    params={"limit": 50},
    headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
messages = response.json()["data"]

:::

Returns a list object of Message objects.

Post a message

Posts Markdown to the workstream's room as this API key. To reply in a thread, pass the ID of the message you're replying to as reply_to.

POST /v1/workstreams/{workstream}/messages

Scope: messages:write · Accepts Idempotency-Key

Parameter In Type Description
workstream path string The workstream's id or slug.

The request body takes these fields:

Body field Type Description
text string The message in Markdown, 1–16,000 characters.
reply_to string, optional The ID of a message in this room. The new message is posted in its thread.

::: code-group

curl https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages \
  -H "Authorization: Bearer $NIMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: build-8812-status" \
  -d '{"text": "Nightly build **passed** on `main` (build 8812)."}'
const response = await fetch('https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NIMBUS_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'build-8812-status',
  },
  body: JSON.stringify({ text: 'Nightly build **passed** on `main` (build 8812).' }),
})
const message = await response.json()
response = requests.post(
    "https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages",
    headers={
        "Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}",
        "Idempotency-Key": "build-8812-status",
    },
    json={"text": "Nightly build **passed** on `main` (build 8812)."},
)
message = response.json()

:::

Returns 201 with the new Message object. Its author.type is api_key and author.name is the key's name, so name keys for what people should see, such as CI status bot.

Edit a message

Replaces the text of a message this API key posted. Messages from people, the agent, Apps, or other keys can't be edited through the API; trying fails with 404 resource_missing.

PATCH /v1/workstreams/{workstream}/messages/{message}

Scope: messages:write

Parameter In Type Description
workstream path string The workstream's id or slug.
message path string The message's ID.

The request body takes one field:

Body field Type Description
text string The new text in Markdown, 1–16,000 characters.

::: code-group

curl -X PATCH https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages/9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64 \
  -H "Authorization: Bearer $NIMBUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Nightly build **failed** on `main` (build 8812): 2 tests."}'
const messageId = '9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64'
const response = await fetch(`https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages/${messageId}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.NIMBUS_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ text: 'Nightly build **failed** on `main` (build 8812): 2 tests.' }),
})
const message = await response.json()
message_id = "9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64"
response = requests.patch(
    f"https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages/{message_id}",
    headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
    json={"text": "Nightly build **failed** on `main` (build 8812): 2 tests."},
)
message = response.json()

:::

Returns the updated Message object, with edited set to true. People in the room see the edit live.

List replies

Returns the thread under a message, oldest first, so it reads top to bottom.

GET /v1/workstreams/{workstream}/messages/{message}/replies

Scope: messages:read

Parameter In Type Description
workstream path string The workstream's id or slug.
message path string The ID of the message that starts the thread.
limit query integer, optional How many messages to return, 1–100. Default 20.
cursor query string, optional The next_cursor from the previous page.

::: code-group

curl https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages/9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64/replies \
  -H "Authorization: Bearer $NIMBUS_API_KEY"
const messageId = '9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64'
const response = await fetch(
  `https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages/${messageId}/replies`,
  { headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` } },
)
const { data: replies } = await response.json()
message_id = "9a4f1c3e-6b2d-4e8a-b7c5-1d0e3f2a8b64"
response = requests.get(
    f"https://api.gonimbus.ai/v1/workstreams/q4-pricing-review/messages/{message_id}/replies",
    headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
replies = response.json()["data"]

:::

Returns a list object of Message objects.

Example scenario

A deployment pipeline posts "Deploying v2.14 to production…" to the release workstream and keeps the returned id. When the deploy finishes, it edits that message to "Deployed v2.14" instead of posting a second one, and posts any warnings as replies with reply_to, so the room gets one tidy update per release. Each post sends an Idempotency-Key built from the release number, so a retried pipeline step never posts twice.

FAQ

Can a key post as a person or as the agent?

No. Messages posted with a key always show the key as their author, with author.type set to api_key. Rename the key on the Developers page to change the name people see on its future messages.

Do people get notified when a key posts?

The message appears live in the room for everyone there, the same way a teammate's message does.

How do I get new messages as they arrive, instead of polling?

Subscribe a webhook endpoint to message.created and message.updated. Each event carries the Message object.

Can I delete a message through the API?

No, there's no delete endpoint. Edit the message instead, or delete it in the app.

Can I read direct messages or Conflux rooms?

No. These endpoints reach workstream rooms only, in workstreams the key can reach.