Workstreams
Reference article: Part of the API reference. For what workstreams are in the app, see What is a workstream.
A workstream is where a piece of work lives in Nimbus: its room, its runs, its decisions, and the context the agent uses. These endpoints list, create, rename, archive, and delete workstreams. Most other resources, such as messages, the agent, and decisions, are reached through a workstream.
Which workstreams a key can reach
An API key doesn't see every workstream in your organization. It reaches:
- Workstreams it was granted on the Developers page, by an admin who can open that workstream. See Workstream access.
- Workstreams it created itself, through Create a workstream.
Every other workstream behaves as if it doesn't exist: a request for it fails with 404 and the code resource_missing, not 403. The same applies to anything inside it, such as its messages and decisions. This way a key can't learn which workstreams exist outside its reach.
Wherever a path has {workstream}, you can pass the workstream's id or its slug.
The Workstream object
{
"id": "3f6c2a1e-8b4d-4e2f-9a7c-5d1b0e6f2a94",
"object": "workstream",
"name": "Q4 pricing review",
"slug": "q4-pricing-review",
"workspace": "default",
"status": "active",
"type": null,
"run_count": 12,
"active_run_count": 1,
"last_activity_at": 1758792310,
"created": 1756201845,
"updated": 1758790022
}
| Field | Type | Description |
|---|---|---|
id |
string | The workstream's ID, a UUID. |
object |
string | Always workstream. |
name |
string or null | Its display name. |
slug |
string or null | Its URL-friendly name. Usable in place of id in paths. |
workspace |
string | The workspace it belongs to. |
status |
string | active, archived, or pending_deletion (deleted and in the trash). |
type |
string or null | The workstream's type, when it has one. |
run_count |
integer | How many runs it has had. |
active_run_count |
integer | How many runs are in progress now. |
last_activity_at |
integer or null | When something last happened in it, in Unix seconds. |
created |
integer | When it was created, in Unix seconds. |
updated |
integer or null | When it was last changed, in Unix seconds. |
List workstreams
Returns the workstreams this key can reach, newest first. Deleted workstreams are left out.
GET /v1/workstreams
Scope: workstreams:read
| Parameter | In | Type | Description |
|---|---|---|---|
limit |
query | integer, optional | How many objects to return, 1–100. Default 20. |
cursor |
query | string, optional | The next_cursor from the previous page. See Pagination. |
status |
query | string, optional | Only workstreams with this status: active or archived. |
workspace |
query | string, optional | Only workstreams in this workspace. |
::: code-group
curl "https://api.gonimbus.ai/v1/workstreams?status=active&limit=50" \
-H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/workstreams?status=active&limit=50', {
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const { data, has_more, next_cursor } = await response.json()
response = requests.get(
"https://api.gonimbus.ai/v1/workstreams",
params={"status": "active", "limit": 50},
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
page = response.json()
:::
Returns a list object of Workstream objects.
Create a workstream
Creates a workstream. The key that creates it can reach it straight away, and so can every other key it's granted to later.
POST /v1/workstreams
Scope: workstreams:write · Accepts Idempotency-Key
| Body field | Type | Description |
|---|---|---|
name |
string | The display name, 1–120 characters. |
workspace |
string, optional | The workspace to create it in. Defaults to your default workspace. |
A new workstream counts toward your plan's limit on live workstreams. Over the limit, the request fails with 402 and the code live_workstream_limit_exceeded. Archive or delete a workstream to free a slot, or upgrade your plan.
::: code-group
curl https://api.gonimbus.ai/v1/workstreams \
-H "Authorization: Bearer $NIMBUS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7d3e9a52-1f4b-4c6d-8e2a-0b5c7f9d1e36" \
-d '{"name": "Q4 pricing review"}'
const response = await fetch('https://api.gonimbus.ai/v1/workstreams', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NIMBUS_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({ name: 'Q4 pricing review' }),
})
const workstream = await response.json()
response = requests.post(
"https://api.gonimbus.ai/v1/workstreams",
headers={
"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"name": "Q4 pricing review"},
)
workstream = response.json()
:::
Returns 201 with the new Workstream object.
Retrieve a workstream
GET /v1/workstreams/{workstream}
Scope: workstreams:read
| Parameter | In | Type | Description |
|---|---|---|---|
workstream |
path | string | The workstream's id or slug. |
::: code-group
curl https://api.gonimbus.ai/v1/workstreams/q4-pricing-review \
-H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/workstreams/q4-pricing-review', {
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const workstream = await response.json()
response = requests.get(
"https://api.gonimbus.ai/v1/workstreams/q4-pricing-review",
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
workstream = response.json()
:::
Returns the Workstream object. A deleted workstream is still returned, with status set to pending_deletion, until it is purged.
Update a workstream
Renames a workstream, or archives or unarchives it. Send only the fields you want to change; a request with neither returns the workstream unchanged.
PATCH /v1/workstreams/{workstream}
Scope: workstreams:write
| Parameter | In | Type | Description |
|---|---|---|---|
workstream |
path | string | The workstream's id or slug. |
The request body takes these fields:
| Body field | Type | Description |
|---|---|---|
name |
string, optional | The new display name, 1–120 characters. |
status |
string, optional | archived to archive it, active to unarchive it. |
::: code-group
curl -X PATCH https://api.gonimbus.ai/v1/workstreams/q4-pricing-review \
-H "Authorization: Bearer $NIMBUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "archived"}'
const response = await fetch('https://api.gonimbus.ai/v1/workstreams/q4-pricing-review', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.NIMBUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: 'archived' }),
})
const workstream = await response.json()
response = requests.patch(
"https://api.gonimbus.ai/v1/workstreams/q4-pricing-review",
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
json={"status": "archived"},
)
workstream = response.json()
:::
Returns the updated Workstream object.
Delete a workstream
Moves the workstream to the trash. An organization admin can restore it in the app until it is purged. While it's in the trash, it's left out of List workstreams, and Retrieve a workstream returns it with status set to pending_deletion.
DELETE /v1/workstreams/{workstream}
Scope: workstreams:write
| Parameter | In | Type | Description |
|---|---|---|---|
workstream |
path | string | The workstream's id or slug. |
::: code-group
curl -X DELETE https://api.gonimbus.ai/v1/workstreams/q4-pricing-review \
-H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/workstreams/q4-pricing-review', {
method: 'DELETE',
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const deleted = await response.json()
response = requests.delete(
"https://api.gonimbus.ai/v1/workstreams/q4-pricing-review",
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
deleted = response.json()
:::
{
"id": "3f6c2a1e-8b4d-4e2f-9a7c-5d1b0e6f2a94",
"object": "workstream",
"deleted": true
}
Errors
| Status | Code | When |
|---|---|---|
400 |
parameter_invalid |
A field is the wrong type or out of range, such as a name over 120 characters. |
400 |
parameter_unknown |
The body has a field these endpoints don't take. |
402 |
live_workstream_limit_exceeded |
Creating it would go over your plan's live workstream limit. |
403 |
insufficient_scope |
The key lacks workstreams:read or workstreams:write. |
404 |
resource_missing |
No workstream has that id or slug, or the key can't reach it. |
FAQ
Why does List workstreams return fewer workstreams than I see in the app?
A key only reaches the workstreams it was granted and the ones it created. An admin can grant it more from the key's ⋯ menu on the Developers page, under Workstream access…. See Workstream access.
Why do I get 404 for a workstream I know exists?
Either the key hasn't been granted it, or the id or slug is wrong. The API answers both the same way, with resource_missing, so it never reveals workstreams outside a key's reach.
Can I use the slug instead of the id?
Yes, anywhere a path takes {workstream}, and in the workstream filter of List runs. Store the id, though: it's what other objects, such as runs and messages, use to refer to the workstream.
Can I restore a deleted workstream through the API?
No. An organization admin can restore it from the trash in the app until it's purged.
Does archiving a workstream free a slot on my plan?
Yes. Archived and deleted workstreams don't count as live, so archiving one makes room to create another without hitting live_workstream_limit_exceeded.