Human approval
WOML
<approval
id="managerApproval"
name="Manager approval"
description="Approve the calculated refund."
timeout="24h"
on-timeout="reject"
>
<notify>
<telegram
chats="123456789"
bot-token="{{secrets.TELEGRAM_BOT_TOKEN}}"
/>
</notify>
<when-approved>
<step id="sendRefund"><script>return issueRefund();</script></step>
</when-approved>
<when-rejected>
<step id="recordRejection"><script>return { rejected: true };</script></step>
</when-rejected>
</approval>| Attribute | Required | Meaning |
|---|---|---|
id | Yes | Waiting-node and context.steps.<id> output identity. |
name, description | No | Human-facing decision context. |
timeout | No | Maximum durable wait. Omission means no WOML deadline. |
on-timeout | No | reject or fail; defaults to fail and requires timeout. |
Child order is fixed: optional <notify>, required <when-approved>, required <when-rejected>. Decision arms may be empty; an empty selected arm is a successful no-op.
WOML persists the wait and opaque capability before notification. Restart does not lose it. The first valid decision wins. Matching repeats are idempotent; an opposing later decision conflicts. The approval result becomes:
JSON
{
"decision": "approved",
"source": "human",
"decidedAt": "2026-08-04T12:00:00.000Z"
}source is human or timeout. on-timeout="reject" publishes a rejected result and runs <when-rejected>. on-timeout="fail" fails the run without executing either arm.
The public decision mechanism is HTTP:
HTTP
POST /api/v1/approvals/{token}/decision
Content-Type: application/json
{ "decision": "approved" }Valid decisions are exactly approved and rejected. There is no npm API or woml.resume() function.