---
title: "How do I wake a suspended run with reply or resume?"
description: "TL;DR: When a run is suspended, continue the same runId with POST /api/runs/:id/reply (HITL / waitForInput) or POST /api/runs/:id/resume (operator pause). Copy requestId from state.resume or the SSE input_request event — never invent it. Slack and email are notifiers that call the same /reply contract."
canonical_url: "https://docs.ballet.dev/articles/how-do-i-wake-a-suspended-run-with-reply-or-resume-EDYuheV1x4"
md_url: "https://docs.ballet.dev/articles/how-do-i-wake-a-suspended-run-with-reply-or-resume-EDYuheV1x4.md"
---
# How do I wake a suspended run with reply or resume?

**TL;DR:** When a run is `suspended`, continue the **same** `runId` with `POST /api/runs/:id/reply` (HITL / `waitForInput`) or `POST /api/runs/:id/resume` (operator pause). Copy `requestId` from `state.resume` or the SSE `input_request` event — never invent it. Slack and email are notifiers that call the same `/reply` contract.

## Who this is for

Developers building Studio clients, Slack/email notifiers, or backend workers that continue parked runs.

## How do I discover a parked run?


1. Keep the `runId` from execute / webhook.
2. Poll `GET /api/runs/:runId` or listen on the run SSE stream until `status === "suspended"`.
3. Read `state.resume` (or the SSE `input_request` event):

Studio History shows the same fields and an API curl snippet. See also [How do I stream playbook run events?](/articles/how-do-i-stream-playbook-run-events-SsXLWiWt9X).

## How do I wake HITL (`waitForInput`)?

Prefer **reply** when `reason` is `input_request`:

```http
POST /api/runs/:runId/reply
Authorization: Bearer <token>
Content-Type: application/json

{
  "requestId": "<from state.resume.requestId>",
  "reply": { "id": "approve", "label": "Approve" }
}
```

**Effect:** wakes the same run and injects `reply` so `waitForInput` returns that value in the re-entered step. Later steps do not see the reply.

Operator pause must **not** use `/reply` — you get `409 reply_not_accepted`. Use `/resume` instead.

```bash
# Discover
curl -s -H "Authorization: Bearer $BALLET_API_TOKEN" \
  "$API/runs/$RUN_ID" | jq '.status, .state.resume'

# Continue (HITL)
curl -s --request POST \
  --url "$API/runs/$RUN_ID/reply" \
  --header "Authorization: Bearer $BALLET_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"requestId":"<state.resume.requestId>","reply":{"id":"approve","label":"Approve"}}'
```

## How do I wake an operator pause?

```http
POST /api/runs/:runId/resume
Authorization: Bearer <token>
Content-Type: application/json

{}
```

Optional body: `{ "fromStepId": "...", "input": {} }`.

For **operator pause**, no reply is injected (so a later `waitForInput` is not auto-answered). `/resume` also continues failed/cancelled runs from a step.

## Common error codes

Treat `request_mismatch` / `wake_conflict` as already-answered for idempotent UX.

## How do Slack / email notifiers work?

Notifiers are delivery UIs for the same park:


1. Detect park (`input_request` SSE, webhook, or poll until `suspended`).
2. Read `runId`, `requestId`, `prompt`, `details`, `schema.options`.
3. Post Approve/Reject (embed server-issued ids in the button or link).
4. On click → `POST /api/runs/:runId/reply` with `{ requestId, reply }`.

Do **not** invent a custom pause API inside step code, and do not busy-wait on Slack from the sandbox.

## How does this compare to Temporal and UiPath?

Same idea: **stable run identity + server-issued wait token + payload**.

Ballet's `requestId` is the UiPath `taskId` / Temporal signal-correlation equivalent.

## Related articles

* [How do I pause and resume a playbook run?](/articles/how-do-i-pause-and-resume-a-playbook-run-TK6ueiBF0d)
* [How do I stream playbook run events?](/articles/how-do-i-stream-playbook-run-events-SsXLWiWt9X)
* [How do I run a playbook over the REST API?](/articles/how-do-i-run-a-playbook-over-the-rest-api-KQIz0apagm)
* [How do I authenticate with the Ballet API?](/articles/how-do-i-authenticate-with-the-ballet-api-tWaqCPLyGT)
* [Ballet vs Temporal](/articles/ballet-vs-temporal-ALEUi3q519)
* [Ballet vs UiPath](/articles/ballet-vs-uipath-V1vXUGHLpb)
