Loops
Reference article: Part of the API reference.
A loop is recurring work with an objective and triggers, such as a schedule, that decide when it runs. Each time a loop fires, Nimbus records an execution, which may start a run. These endpoints list loops and their executions, and let you fire a loop from your own systems, for example when a file lands or a deal closes.
Loops that their owner keeps private aren't visible to API keys. Loops shared with the organization are.
The Loop object
{
"id": "6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58",
"object": "loop",
"name": "Weekly supplier price check",
"objective": "Flag any supplier price change over 3% since last week.",
"workstream": "3f6c2a1e-8b4d-4e2f-9a7c-5d1b0e6f2a94",
"status": "active",
"triggers": ["schedule"],
"created": 1756201845,
"updated": 1758190022
}
| Field | Type | Description |
|---|---|---|
id |
string | The loop's ID. |
object |
string | Always loop. |
name |
string | Its display name. |
objective |
string | What the loop is for, in its owner's words. |
workstream |
string or null | The ID of the workstream it works in, if it has one. |
status |
string | draft, active, paused, or archived. |
triggers |
string[] | The kinds of trigger that fire it, such as schedule or webhook. |
created |
integer or null | When it was created, in Unix seconds. |
updated |
integer or null | When it last changed, in Unix seconds. |
The LoopExecution object
{
"id": "e3a8c5d2-9f1b-4e7a-b6c0-4d2f8a1e5b93",
"object": "loop_execution",
"loop": "6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58",
"trigger": "manual",
"status": "running",
"run": "c1d7e4a9-3b8f-4c2e-9d6a-8f0b5e2c7a13",
"reason": null,
"created": 1758792310,
"completed": null
}
| Field | Type | Description |
|---|---|---|
id |
string | The execution's ID. |
object |
string | Always loop_execution. |
loop |
string | The ID of the loop. |
trigger |
string | What fired it. Executions started through the API show manual. |
status |
string | pending, skipped, running, completed, or failed. |
run |
string or null | The ID of the run it started, if any. |
reason |
string or null | Why it was skipped or failed. |
created |
integer or null | When it started, in Unix seconds. |
completed |
integer or null | When it finished, in Unix seconds. |
skipped means the loop decided there was nothing to do, for example because nothing changed since its last execution. reason says why.
List loops
Returns the loops visible to API keys, newest first.
GET /v1/loops
Scope: loops: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 loops with this status: draft, active, paused, or archived. |
::: code-group
curl "https://api.gonimbus.ai/v1/loops?status=active" \
-H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/loops?status=active', {
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const { data: loops } = await response.json()
response = requests.get(
"https://api.gonimbus.ai/v1/loops",
params={"status": "active"},
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
loops = response.json()["data"]
:::
Returns a list object of Loop objects.
Retrieve a loop
GET /v1/loops/{loop}
Scope: loops:read
| Parameter | In | Type | Description |
|---|---|---|---|
loop |
path | string | The loop's ID. |
::: code-group
curl https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58 \
-H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58', {
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const loop = await response.json()
response = requests.get(
"https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58",
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
loop = response.json()
:::
Returns the Loop object.
List a loop's executions {#list-a-loops-executions}
Returns a loop's executions, newest first.
GET /v1/loops/{loop}/executions
Scope: loops:read
| Parameter | In | Type | Description |
|---|---|---|---|
loop |
path | string | The loop's ID. |
limit |
query | integer, optional | How many objects 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/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58/executions \
-H "Authorization: Bearer $NIMBUS_API_KEY"
const response = await fetch('https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58/executions', {
headers: { Authorization: `Bearer ${process.env.NIMBUS_API_KEY}` },
})
const { data: executions } = await response.json()
response = requests.get(
"https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58/executions",
headers={"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}"},
)
executions = response.json()["data"]
:::
Returns a list object of LoopExecution objects.
Run a loop now
Fires the loop as if its trigger had fired. Whatever you pass as input reaches the loop as its trigger payload, so the loop can act on it.
POST /v1/loops/{loop}/execute
Scope: loops:write · Accepts Idempotency-Key
| Parameter | In | Type | Description |
|---|---|---|---|
loop |
path | string | The loop's ID. |
The request body is optional and takes these fields:
| Body field | Type | Description |
|---|---|---|
input |
object, optional | The trigger payload: any JSON object, up to 64 KB. If it has no source field, Nimbus adds "source": "public_api"; a source you send is kept. |
force |
boolean, optional | true to run even if nothing changed since the last execution. |
::: code-group
curl https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58/execute \
-H "Authorization: Bearer $NIMBUS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: price-file-2026-09-25" \
-d '{"input": {"file": "prices/2026-09-25.csv", "supplier_count": 42}}'
const response = await fetch('https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58/execute', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NIMBUS_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'price-file-2026-09-25',
},
body: JSON.stringify({ input: { file: 'prices/2026-09-25.csv', supplier_count: 42 } }),
})
const execution = await response.json()
response = requests.post(
"https://api.gonimbus.ai/v1/loops/6b9e2f41-0c7d-4a5b-8e3f-2d1a9c4b7e58/execute",
headers={
"Authorization": f"Bearer {os.environ['NIMBUS_API_KEY']}",
"Idempotency-Key": "price-file-2026-09-25",
},
json={"input": {"file": "prices/2026-09-25.csv", "supplier_count": 42}},
)
execution = response.json()
:::
Returns 201 with the new LoopExecution. Its status may already be skipped, with a reason, if the loop found nothing to do; send "force": true to run it anyway. An input over 64 KB fails with 400 parameter_invalid.
Example scenario
A finance team drops a supplier price file into cloud storage every Monday. Their storage system calls a small function that runs the loop now with the file's path as input, and an Idempotency-Key made from the file name, so a storage event delivered twice can't fire the loop twice. The loop compares prices and, when something changed, starts a run whose report lands in the workstream. The function stores the execution's run and reports back when the run completes.
FAQ
Why can't I see a loop that's in the app?
Its owner keeps it private. Loops shared with the organization are visible to API keys; private ones aren't. Ask the owner to share it if an integration needs it.
What does force do?
A loop can skip an execution when nothing has changed since the last one. force: true runs it regardless.
Does running a loop through the API use NTUs?
The work the loop does, such as the run it starts, uses NTUs the same way it would if the loop fired on its own schedule.
How do I know when an execution finishes?
List the loop's executions, or retrieve the run named in run and watch its status. Subscribing a webhook endpoint to run.completed and run.failed tells you without polling.
Can I create or edit loops through the API?
No. Create and change loops in the app; the API lists them and runs them.