POST /v1/routines/runs/{run_id}/replay
Starts a new run of a finished run's routine that reuses what the source run already did. Each top-level step that succeeded in the source run is copied: it succeeds at once with its recorded outputs, does not run its callable again (no request, no sandbox, no charge) and shows `replayed: true`. Everything else runs: `from_step` and every step downstream of it, the steps that failed, were skipped or were canceled, steps another version adds or changes (compared with the source version's step of the same id: the step as written, the pack and routine versions it pinned at publish, the steps it depends on, and the `vars` and `env` it reads), steps that read an `input` that differs from the source's (directly or through `env`), steps that wait for a signal unless the version and input are the source's, and every step downstream of one of those. `trigger` and `run` are not compared. Without `from_step`, a replay of a failed run picks up where it failed. The new run uses the source run's version and input unless `version` or `input` is given, so a fix published as a new version can be replayed against the run that failed. Its trigger is `{type: replay, parent_run_id, from_step}`; steps that run again read what the source got from its trigger through the input. Copied steps do not count toward `routines.steps.daily`. The copied outputs and the input together are at most `routines.max_step_output_bytes` (1 MiB by default), or the replay answers 422 `replay_too_large`. Answers like `routinesCreateRun`: `?wait=`, `Accept: text/event-stream`, `webhook` and `Idempotency-Key` work the same way.

Authentication

Bearer Token (b3os_sk_ API key or b3os_pat_ token)

Path Parameters

run_id string required path
The run ID (`run_…`).
Example: "run_01m5t5fr06dx6azc42f4wbzf5s"

Query Parameters

wait integer optional query
Seconds to wait for the job to finish before responding, from 0 to 60. If it finishes in time the response is `200` with the finished job; otherwise `202` with the job as it is, a `Location` to poll and `Retry-After`. `0` (the default) returns immediately.

Header Parameters

Idempotency-Key string optional header
A unique value (for example a UUID) that makes this request safe to retry. Scoped to your project for 24 hours: a retry with the same key, method, path and body returns the stored response with `Idempotent-Replayed: true`, and only to the same API key. Reusing the key for a different request returns `409 idempotency_key_conflict`. A retry that arrives while the first request runs gets `409 idempotency_request_in_progress` with `Retry-After`. The first request runs to completion and its response is stored even if your client disconnects. A node keeps a bounded number of keys per organization: past that bound a request with a new key is refused (`429 quota_exceeded`, retryable) rather than run without its key. When a node is full, organizations holding more than their share may have their oldest stored responses dropped; a retry with such a key gets `409 idempotency_response_evicted` and is not run again.

Request Body

application/json
from_step string
Run this top-level step and every step downstream of it again. Absent: only the steps that did not succeed, and those downstream of them, run again.
input object
The new run's input instead of the source run's; validated against the version's `inputs`. When it differs from the source's, the steps that read it (directly or through `env`) and the steps that wait for a signal run again, with every step downstream of them.
version string | integer
Replay with this version instead of the source run's (`ver_` ID or number). The steps it adds or changes and the steps that wait for a signal run again, with every step downstream of them.
One of:
Option 1string
Option 2integer
durability string
Override the version's default durability for the new run.
Enum: ephemeral, standard, strict
webhook object
Where to deliver this job's events. Deliveries are `POST`s of a `WebhookEvent` signed with `B3OS-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">` using the endpoint's secret (`POST /v1/webhooks/secret`). Failed deliveries are retried with backoff for 24 hours. Delivery goes through the egress guard, so private and loopback addresses are refused.
url string (uri) REQUIRED
An `https://` URL.
events string[]
Event types to deliver. Defaults to the terminal events (`job.succeeded`, `job.failed`, `job.canceled`); `["*"]` delivers every event.
Array of: string
metadata object
Up to 16 string key-value pairs you attach to an object for your own use. Keys are 1 to 40 characters of `A-Z a-z 0-9 _ . : -`; values are at most 500 characters. B3OS never interprets them.

Responses

200 The new run finished within `wait` seconds, or the event stream when `Accept` is `text/event-stream`.
application/json
id string REQUIRED
object string REQUIRED
Enum: routine_run
status string REQUIRED
`queued` → `running` → one of the terminal statuses `succeeded`, `failed` or `canceled`. A job never leaves a terminal status.
Enum: queued, running, succeeded, failed, canceled
created_at string (date-time) REQUIRED
updated_at string (date-time) REQUIRED
started_at string (date-time) | null
finished_at string (date-time) | null
progress object
How far a job has got, in the job's own unit (pages, items, steps).
completed integer REQUIRED
Units finished, successfully or not.
failed integer
Units that failed (included in `completed`).
total integer | null
Units expected, when known.
unit string REQUIRED
What is counted, such as `pages`, `items` or `steps`.
result unknown
The job's output. Present once `status` is `succeeded`; the product's job type defines its shape.
error object
An RFC 9457 problem. `code` is stable and listed in the errors catalog; `type` links to its entry. `detail` is human-readable and may change. Extension members appear only for the codes that document them; ignore members you do not recognize.
type string (uri) REQUIRED
`https://docs.beta.b3os.org/errors#<code>`.
title string REQUIRED
Short summary of the problem type.
status integer REQUIRED
The HTTP status code, repeated for convenience.
code string REQUIRED
Stable machine-readable error code from the errors catalog.
detail string REQUIRED
Explanation of this occurrence. Never contains secrets.
instance string
The request ID (`req_…`) of the request that failed. Include it when you contact support.
errors object[]
Validation problems, one per field (`invalid_request` and the other codes that list `errors`).
Array of:
pointer string REQUIRED
Where the problem is: a JSON pointer into the request body (`/url`, `/steps/0/uses`), or `#query/<name>`, `#path/<name>` or `#header/<name>` for parameters.
detail string REQUIRED
What is wrong there.
reason string
Finer-grained cause for codes that document one (`unauthorized`, `forbidden`, `egress_denied`, `upstream_unreachable`, …).
required_scope string
The scope that was missing (`forbidden` with `reason: scope`).
retry_after_s integer
Same value as the `Retry-After` header, for clients that only read the body.
limit object
The limit an error refers to. IDs and current values are listed by `GET /v1/limits`.
id string REQUIRED
Limit ID, such as `vision.scrape.rpm` or `sandboxes.concurrent`.
limit number REQUIRED
The limit's value.
unit string REQUIRED
What the limit counts, such as `requests`, `sandboxes`, `vcpu` or `MiB`.
window_s integer
Window length in seconds for rate limits and quotas.
current number
Current usage against the limit, when known.
current_status string
The object's current status, for state conflicts such as `sandbox_not_running`.
upstream_status integer
The HTTP status the upstream returned (`upstream_error`, `action_output_invalid`).
step string
The failed step, as a step ID (routines), an index (`act`) or a path such as `beats/2/do/0` (render).
pack_error object
The error a pack's error mapping chose (`upstream_error` from pack actions).
code string REQUIRED
message string REQUIRED
retryable boolean REQUIRED
timing object
Server-side phase durations in milliseconds with microsecond resolution: the same phases as the `Server-Timing` header, keyed `<phase>_ms`. `total_ms` is always present. Phase names are product-specific and documented per operation. Example values in this reference are illustrative, not measurements.
total_ms number REQUIRED
expires_at string (date-time) | null
When the job's results are deleted (retention); `null` while the job is not terminal.
metadata object
Up to 16 string key-value pairs you attach to an object for your own use. Keys are 1 to 40 characters of `A-Z a-z 0-9 _ . : -`; values are at most 500 characters. B3OS never interprets them.
webhook object
Where to deliver this job's events. Deliveries are `POST`s of a `WebhookEvent` signed with `B3OS-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">` using the endpoint's secret (`POST /v1/webhooks/secret`). Failed deliveries are retried with backoff for 24 hours. Delivery goes through the egress guard, so private and loopback addresses are refused.
url string (uri) REQUIRED
An `https://` URL.
events string[]
Event types to deliver. Defaults to the terminal events (`job.succeeded`, `job.failed`, `job.canceled`); `["*"]` delivers every event.
Array of: string
routine_id string REQUIRED
version_id string REQUIRED
version_number integer REQUIRED
durability string REQUIRED
Enum: ephemeral, standard, strict
trigger object REQUIRED
How the run started (the `trigger` context of its expressions).
type string REQUIRED
Enum: api, cron, interval, webhook, action, routine, replay
id string
The trigger ID (cron, interval, webhook, action).
occurrence_id string
Cron and interval occurrence, used to deduplicate fires.
scheduled_at string (date-time)
hook_id string
delivery_id string
subscription_id string
The trigger subscription that delivered the event (action triggers).
event_id string
The pack trigger event's ID (action triggers).
parent_run_id string
For sub-routine runs, the calling run; for replays, the source run.
parent_step_id string
from_step string
For replays started with `from_step`, that step.
input object REQUIRED
summary string
The run's outcome line: when the routine's `output` is an object with a non-empty `summary` string, that string on one line, cut to 140 characters (an ellipsis marks the cut). Absent otherwise. Run lists, the run's terminal event and its webhook carry it, so a list of runs says what each one did.
steps object[] REQUIRED
Top-level steps in definition order.
Array of:
id string REQUIRED
The step ID from the definition.
uses string
item_index integer
Position in the map's list, for steps inside a map body.
status string REQUIRED
Enum: pending, running, waiting, retrying, succeeded, failed, skipped, canceled
attempt integer REQUIRED
The attempt this execution is. Retries add one; so does a node restart while the step ran (the earlier attempt's result, should it arrive, is discarded).
started_at string (date-time)
finished_at string (date-time)
duration_ms number
outputs unknown
The step's outputs, once it succeeded.
error object
An RFC 9457 problem. `code` is stable and listed in the errors catalog; `type` links to its entry. `detail` is human-readable and may change. Extension members appear only for the codes that document them; ignore members you do not recognize.
type string (uri) REQUIRED
`https://docs.beta.b3os.org/errors#<code>`.
title string REQUIRED
Short summary of the problem type.
status integer REQUIRED
The HTTP status code, repeated for convenience.
code string REQUIRED
Stable machine-readable error code from the errors catalog.
detail string REQUIRED
Explanation of this occurrence. Never contains secrets.
instance string
The request ID (`req_…`) of the request that failed. Include it when you contact support.
errors object[]
Validation problems, one per field (`invalid_request` and the other codes that list `errors`).
Array of:
pointer string REQUIRED
Where the problem is: a JSON pointer into the request body (`/url`, `/steps/0/uses`), or `#query/<name>`, `#path/<name>` or `#header/<name>` for parameters.
detail string REQUIRED
What is wrong there.
reason string
Finer-grained cause for codes that document one (`unauthorized`, `forbidden`, `egress_denied`, `upstream_unreachable`, …).
required_scope string
The scope that was missing (`forbidden` with `reason: scope`).
retry_after_s integer
Same value as the `Retry-After` header, for clients that only read the body.
limit object
The limit an error refers to. IDs and current values are listed by `GET /v1/limits`.
id string REQUIRED
Limit ID, such as `vision.scrape.rpm` or `sandboxes.concurrent`.
limit number REQUIRED
The limit's value.
unit string REQUIRED
What the limit counts, such as `requests`, `sandboxes`, `vcpu` or `MiB`.
window_s integer
Window length in seconds for rate limits and quotas.
current number
Current usage against the limit, when known.
current_status string
The object's current status, for state conflicts such as `sandbox_not_running`.
upstream_status integer
The HTTP status the upstream returned (`upstream_error`, `action_output_invalid`).
step string
The failed step, as a step ID (routines), an index (`act`) or a path such as `beats/2/do/0` (render).
pack_error object
The error a pack's error mapping chose (`upstream_error` from pack actions).
code string REQUIRED
message string REQUIRED
retryable boolean REQUIRED
map object
Item counts for a map step.
total integer
succeeded integer
failed integer
running integer
waiting_for object
What a waiting step waits for.
signal string
until string (date-time)
replayed boolean
A replay copied this step's outputs from its source run; the step did not run. Absent otherwise.
Enum: true
202 The new run was accepted and is still running.
400 `from_step` names no top-level step of the version (`invalid_request`, with `errors`).
401 Missing, malformed, expired or revoked credentials (`unauthorized`).
402 The organization has no credits left, or the key reached its spend cap.
403 The key that published the active version is revoked (`run_as_revoked`).
404 No such run in this project (`run_not_found`).
409 The source run is still `queued` or `running` (`run_not_finished`), or the `Idempotency-Key` was used for a different request (`idempotency_key_conflict`).
413 The request body exceeds this operation's limit.
415 The Content-Type is not accepted by this operation.
422 The input does not match the version's `inputs` schema (`run_input_invalid`), `webhook.url` is not an absolute `https://` URL (`invalid_webhook_url`), or the copied outputs with the input are over `routines.max_step_output_bytes` (`replay_too_large`).
429 A rate, concurrency or quota limit applies (`rate_limited`, `concurrency_limited`, `quota_exceeded`).
500 Something failed inside B3OS (`internal`). Retry with backoff.
503 The node or the product is not available right now (`node_unavailable`, `product_unavailable`, `capacity_unavailable`).
curl -X POST 'https://beta-api.b3os.org/v1/routines/runs/run_01m5t5fr06dx6azc42f4wbzf5s/replay' \  -H 'Authorization: Bearer YOUR_API_TOKEN' \  -H 'Content-Type: application/json' \  -d '{  "from_step": "summary"}'
const response = await fetch('https://beta-api.b3os.org/v1/routines/runs/run_01m5t5fr06dx6azc42f4wbzf5s/replay', {  method: 'POST',  headers: {      "Authorization": "Bearer YOUR_API_TOKEN",      "Content-Type": "application/json"  },  body: JSON.stringify({    "from_step": "summary"  })});const data = await response.json();console.log(data);
import requestsheaders = {    'Authorization': 'Bearer YOUR_API_TOKEN'}response = requests.post('https://beta-api.b3os.org/v1/routines/runs/run_01m5t5fr06dx6azc42f4wbzf5s/replay', headers=headers, json={  "from_step": "summary"})print(response.json())
200 Response
{  "id": "run_01m5t7a3k2xq9zb4c8d6e0f1g2",  "object": "routine_run",  "status": "succeeded",  "routine_id": "rtn_01m5t6vhkw4a8fa4tb5w4ffz37",  "version_id": "ver_01m5t6ncrsssrysy1p2fbn2pgf",  "version_number": 2,  "durability": "standard",  "trigger": {    "type": "replay",    "parent_run_id": "run_01m5t5fr06dx6azc42f4wbzf5s",    "from_step": "summary"  },  "input": {    "topic": "pricing"  },  "result": {    "summary": "Prices did not change today."  },  "summary": "Prices did not change today.",  "steps": [    {      "id": "page",      "uses": "vision/scrape@1",      "status": "succeeded",      "attempt": 1,      "started_at": "2026-10-25T20:10:00.001Z",      "finished_at": "2026-10-25T20:10:00.001Z",      "duration_ms": 0.004,      "replayed": true    },    {      "id": "summary",      "uses": "infer/chat@1",      "status": "succeeded",      "attempt": 1,      "started_at": "2026-10-25T20:10:00.001Z",      "finished_at": "2026-10-25T20:10:01.180Z",      "duration_ms": 1179.2    }  ],  "progress": {    "completed": 2,    "total": 2,    "unit": "steps"  },  "created_at": "2026-10-25T20:10:00.000Z",  "updated_at": "2026-10-25T20:10:01.180Z",  "started_at": "2026-10-25T20:10:00.000Z",  "finished_at": "2026-10-25T20:10:01.180Z",  "timing": {    "dispatch_ms": 0.02,    "steps_ms": 1179.3,    "total_ms": 1180.1  },  "expires_at": "2026-11-24T20:10:01.180Z",  "metadata": {}}
Ask a question... ⌘I