Answer a wait link
Answers the step: it completes with `{signal, payload, received_at, timed_out: false}`, where `payload` is `{decision, approved, comment, via: "link"}`, exactly as if the signal had been sent with `POST /v1/routines/runs/{run_id}/signal`. The first answer wins: the answer is delivered only while the step waits (never buffered), and any later one answers 410 `wait_already_answered`. A step that has not started waiting yet answers 409 `wait_not_ready` with `Retry-After`; a step past its deadline or 7 days, or a run that ended, answers 410 `wait_link_expired`. The page posts its form (`application/x-www-form-urlencoded`) and gets the page back; programs send JSON and get `RoutineWait`.
POST
/v1/routines/waits/{token}
Answers the step: it completes with `{signal, payload, received_at, timed_out: false}`, where `payload` is
`{decision, approved, comment, via: "link"}`, exactly as if the signal had been sent with
`POST /v1/routines/runs/{run_id}/signal`. The first answer wins: the answer is delivered only while the
step waits (never buffered), and any later one answers 410 `wait_already_answered`. A step that has not
started waiting yet answers 409 `wait_not_ready` with `Retry-After`; a step past its deadline or 7 days,
or a run that ended, answers 410 `wait_link_expired`. The page posts its form
(`application/x-www-form-urlencoded`) and gets the page back; programs send JSON and get `RoutineWait`.
Path Parameters
token
string
required
path
The link's token, `<run id>.<step id>.<signature>` (32 base64url characters), from `run.wait_urls.<step id>`. Anything else answers `wait_link_invalid`, so a link cut short in a message still gets the page that says so.
Example:
"run_01m6f0re3gzz9kvb26hebdcd0x.approve.q3Zr0wq9mXk3o1yJb7vH2cT5dN8pLa4e"Request Body required
application/jsondecision
string
REQUIRED
Enum:
approve, rejectcomment
string
Responses
200
The step, answered.
application/jsonobject
string
REQUIRED
Enum:
routine_waitstatus
string
REQUIRED
waiting: it takes an answer. pending: the step has not started waiting. answered: through a link or a signal. timed_out: its deadline passed. expired: 7 days after it started waiting. ended: the run ended, or the step was skipped or canceled, before an answer.
Enum:
waiting, pending, answered, timed_out, expired, endedrun_id
string
REQUIRED
run_status
string
REQUIRED
Enum:
queued, running, succeeded, failed, canceledroutine_id
string
REQUIRED
routine_name
string | null
step_id
string
REQUIRED
step_name
string | null
prompt
object | null
REQUIRED
The step's evaluated prompt while it waits, and after an answer while the node still holds the run (null once the run is only in the run store).
title
string
body
string
image
string (uri)
link
string (uri)
dropped
string[]
Array of:
string
waiting_since
string (date-time) | null
expires_at
string (date-time) | null
While the step waits; its own deadline may end it sooner.
answer
object | null
REQUIRED
Once answered. `decision` is null for a signal sent through the API without one.
decision
string | null
Enum:
approve, reject, nullapproved
boolean | null
comment
string | null
via
string
Enum:
link, signalanswered_at
string (date-time) | null
400
The request failed validation (`invalid_request`, `invalid_url`).
404
The link is not valid (`wait_link_invalid`).
409
The step has not started waiting yet (`wait_not_ready`).
410
The link no longer takes an answer (`wait_already_answered`, `wait_link_expired`).
413
The request body exceeds this operation's limit.
415
The Content-Type is not accepted by this operation.
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/waits/run_01m6f0re3gzz9kvb26hebdcd0x.approve.q3Zr0wq9mXk3o1yJb7vH2cT5dN8pLa4e' \ -H 'Authorization: Bearer YOUR_API_TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "decision": "approve", "comment": "Ship it."}'
const response = await fetch('https://beta-api.b3os.org/v1/routines/waits/run_01m6f0re3gzz9kvb26hebdcd0x.approve.q3Zr0wq9mXk3o1yJb7vH2cT5dN8pLa4e', { method: 'POST', headers: { "Authorization": "Bearer YOUR_API_TOKEN", "Content-Type": "application/json" }, body: JSON.stringify({ "decision": "approve", "comment": "Ship it." })});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/waits/run_01m6f0re3gzz9kvb26hebdcd0x.approve.q3Zr0wq9mXk3o1yJb7vH2cT5dN8pLa4e', headers=headers, json={ "decision": "approve", "comment": "Ship it."})print(response.json())
200
Response
{ "object": "routine_wait", "status": "answered", "run_id": "run_01m6f0re3gzz9kvb26hebdcd0x", "run_status": "running", "routine_id": "rtn_01m5t6vhkw4a8fa4tb5w4ffz37", "routine_name": "launch-card", "step_id": "approve", "step_name": "Approve the card", "prompt": { "title": "Post the launch card to", "body": "The card for 0.4.0 is below. Approve posts it; Reject stops the run here.", "image": "https://usercontent.beta.b3os.org/render/art_01m6f0rf6q8f3d8wq7xr7d1f3p/card.png" }, "waiting_since": null, "expires_at": null, "answer": { "decision": "approve", "approved": true, "comment": "Ship it.", "via": "link", "answered_at": "2026-11-02T22:11:40.512Z" }}
API Playground
Try this endpoint
POST
/v1/routines/waits/{token}