Manage Runs
Poll run status, retrieve results, cancel runs, and implement reliable polling patterns with the Rapidfolio Runner API.
Get Run Status
GET https://run.rapidfolio.com/runs/:runId
Authorization: Bearer <api_key>
Returns the current state of a run, including its inputs, outputs, and timing.
Response
{
"id": "run_clxyz123",
"status": "completed",
"type": "api",
"environment": "sandbox",
"input": { "customerId": "cust_123" },
"output": { "approved": true },
"error": null,
"startedAt": "2026-02-27T10:00:00.000Z",
"completedAt": "2026-02-27T10:00:05.000Z",
"createdAt": "2026-02-27T10:00:00.000Z",
"procedureVersionId": "ver_abc"
}
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | The run ID |
status | string | Current status — see Status Values |
type | string | How the run was triggered: api, trigger, or manual |
environment | string | sandbox or live |
input | object | The input data the run was started with |
output | object | null | The procedure's final output, once completed |
error | string | null | Error message if the run failed or was rejected |
startedAt | string | null | ISO 8601 timestamp when execution began |
completedAt | string | null | ISO 8601 timestamp when the run reached a terminal state |
createdAt | string | ISO 8601 timestamp when the run record was created |
procedureVersionId | string | The specific procedure version that was executed |
Status Values
| Status | Description |
|---|---|
pending | Queued but not yet started |
running | Actively executing |
awaiting_review | Paused at a Human Review node — waiting for a reviewer decision |
completed | Finished successfully — output is populated |
failed | Finished with an error — error describes what went wrong |
cancelled | Manually cancelled before reaching a terminal state |
The terminal statuses are completed, failed, and cancelled. Once a run reaches one of these statuses it will not change again.
Cancel a Run
POST https://run.rapidfolio.com/runs/:runId/cancel
Authorization: Bearer <api_key>
Cancels a run that is in pending or running status. Runs that are awaiting_review can also be cancelled. Runs that have already reached a terminal state (completed, failed, cancelled) cannot be cancelled.
Success Response — 200
{ "success": true }
Error Response — 409
{ "error": "Run is already in a terminal state" }
Polling Pattern
When you start a run in async mode, you receive a runId and a statusUrl. Poll statusUrl until the run reaches a terminal status.
Use exponential backoff to avoid hammering the API — start with a short interval and increase it on each poll.
async function pollUntilDone(
runId: string,
apiKey: string,
options: { initialIntervalMs?: number; maxIntervalMs?: number; timeoutMs?: number } = {}
): Promise<RunResult> {
const {
initialIntervalMs = 1000,
maxIntervalMs = 15000,
timeoutMs = 300000,
} = options
const terminalStatuses = new Set(['completed', 'failed', 'cancelled'])
const startTime = Date.now()
let intervalMs = initialIntervalMs
while (true) {
if (Date.now() - startTime > timeoutMs) {
throw new Error(`Polling timed out after ${timeoutMs}ms for run ${runId}`)
}
await sleep(intervalMs)
const response = await fetch(`https://run.rapidfolio.com/runs/${runId}`, {
headers: { Authorization: `Bearer ${apiKey}` },
})
if (!response.ok) {
throw new Error(`Failed to fetch run status: ${response.status}`)
}
const run = await response.json() as RunResult
if (terminalStatuses.has(run.status)) {
return run
}
// Exponential backoff with jitter
intervalMs = Math.min(intervalMs * 1.5 + Math.random() * 500, maxIntervalMs)
}
}
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms))
}
Tip: If you are polling frequently or have many concurrent runs, consider using webhooks instead. Webhooks push completion events to your server the moment they occur, eliminating polling entirely.
Handling Each Terminal Status
Once polling returns a terminal status, branch on run.status:
const run = await pollUntilDone(runId, apiKey)
switch (run.status) {
case 'completed':
// Use run.output
console.log('Procedure completed:', run.output)
break
case 'failed':
// run.error contains the failure reason
console.error('Procedure failed:', run.error)
break
case 'cancelled':
console.warn('Run was cancelled')
break
}