TL;DR: Ballet can park a playbook run as Paused (suspended) and continue it later on the same run ID. Editors can pause between steps, or a Code step can call metaphor.waitForInput to wait for a human or external signal. Continue from Studio, or wake via the API with a server-issued requestId.
Builders who need human approval, long waits, or a mid-run pause without losing progress.
In both cases:
runId (History shows one row; the badge flips Running → Pausing → Paused → Running).suspended is not a final status — you can Continue or Stop.reason: operator_pause).Use Stop on a paused run to cancel it.
In a Code step, checkpoint expensive work first, then park:
const decision = await metaphor.waitForInput({
prompt: 'Approve this invoice before posting?',
details: extractedFields, // shown in Studio while waiting
schema: {
kind: 'choice',
options: [
{ id: 'approve', label: 'Approve' },
{ id: 'reject', label: 'Reject' },
],
multiSelect: false,
},
});
if (decision?.id === 'reject') {
const result = { ok: false, __next: 'abort' };
} else {
const result = { ok: true, decision };
}
Rules:
details so reviewers (and notifiers) can see what to approve.waitForInput returns the reply payload (for example { id: 'approve', label: 'Approve' }).For HITL parks, the wake payload is the reply body — not a new set of step input mappings.
waitForInput.POST /api/runs/:runId/reply.input on wake to override the run's flow.input for the continued execution.Discover wake parameters from History → run detail (or GET /api/runs/:id) while status is Paused:
Past plays also show an API resume (curl) snippet with runId and requestId filled in.
Slack and email are notifiers for the same park — they are not a second pause API. A notifier posts Approve/Reject, then calls the wake API with the parked requestId. Studio Continue uses that same path.
For the full HTTP contract, curl examples, and notifier pattern, see How do I wake a suspended run with reply or resume?.