> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Wait & Approval

> Pause a workflow until a person approves it or a one-time callback URL is used, then carry on with what they sent — without holding anything open in between.

# Wait for Event

Some automations should not finish on their own. A refund over a threshold wants a
human's say-so. A provisioning run has to wait for a partner system to call back. A
document has to be signed before the next step means anything.

The **Wait for Event** step is that pause. It stops the run, hands out a one-time link,
and does nothing at all until somebody uses it — or until the wait runs out.

## It costs nothing while it waits

A waiting run is not a held connection or a sleeping worker. KnoxCall writes the run's
state to an encrypted checkpoint and puts it down; when the answer arrives, the run picks
up on the very next step with everything it knew before. A wait of thirty seconds and a
wait of three weeks cost the same: nothing.

That is also why a wait survives a deploy, a restart, or a machine going away. There is
no process sitting somewhere holding your place.

## Two modes

### Wait for a callback

The step mints a single-use URL. Whoever holds it can `POST` to it, and whatever they
send becomes the step's output:

```json theme={"dark"}
{
  "resumed": true,
  "timedOut": false,
  "mode": "webhook",
  "payload": { "signed": true, "documentId": "doc_123" },
  "receivedAt": "2026-09-09T04:11:02.114Z"
}
```

The link is emailed to the people you name when the wait begins, and at least one address is
required — email is currently the only way the link leaves KnoxCall, so a callback wait with
nobody to send it to could only ever time out.

### Wait for an approval

The step emails **approve** and **reject** links to the people you list. Each person gets
their own pair, which is what makes the recorded decision trustworthy: the respondent is
the address KnoxCall sent the link to, never something the person typed.

```json theme={"dark"}
{
  "resumed": true,
  "timedOut": false,
  "mode": "approval",
  "approved": true,
  "decision": "approve",
  "respondent": "ops@yourcompany.com",
  "comment": "Checked the invoice — fine to release.",
  "decidedAt": "2026-09-09T04:11:02.114Z"
}
```

The **first decision wins**, and it is enforced rather than merely intended: the answered step
is marked the instant a decision is recorded, so a second link presented in the same breath as
the first is refused and cannot overwrite it. Every other link for that wait then stops working
— including the same person's other button.

## Who KnoxCall will email

Approval and callback mail goes out on **KnoxCall's own signed sender**, because the recipient's
only defence against a forged approval request is that it demonstrably came from us. That puts
two limits on it, both deliberate:

* **The subject line is ours.** It names the workflow and nothing else. There is no field for
  it. Your **Message** still appears in the mail, shown as a quote attributed to your workspace.
* **The recipient must be somebody you can prove a relationship with** — a member of this
  workspace, or an address at (or beneath) a domain you have verified under
  *Settings → Sending domains*. Anything else is refused before the wait starts, and the step
  says which address and why.

To email someone outside both of those — a customer, a partner — use the **Send Email** step on
your own provider credential, where your provider account enforces its own verification.

## The timeout branch

Every wait has a deadline, between one minute and thirty days. When it passes, the run
continues down a **connection labelled `timeout`**:

* draw a connection from the Wait step to whatever should happen when nobody answers;
* open the connection and name it `timeout`.

The other connections leaving the step are the *answered* path, and the two never both
run. Branch on `{{steps.wait.approved}}` after an approval if you want different
behaviour for approve and reject.

If you would rather the run simply stop, set **On timeout** to *Fail the run*. What the
step will not do is quietly go nowhere: if it is set to branch and no `timeout`
connection is wired, the run fails and says so.

## What the links are, and what they are not

A resume link is a **capability**: whoever holds it can continue that one run, once.
Treat it the way you would treat a password reset link.

* The link is 256 bits of randomness. KnoxCall stores only its SHA-256 hash, so the link
  cannot be recovered from our database, our logs, or your run history — it exists in the
  email we sent and nowhere else.
* It works **once**. A second use, a use after the deadline, and a link that never existed
  all get the same "not found": the endpoint will not tell anyone which.
* Clicking it opens a **confirmation page**. Nothing happens until the button on that page
  is pressed, so a mail scanner or link preview that fetches the URL cannot approve
  anything on your behalf.
* It is scoped to one run, one step and one mode. A Test-mode link can never resume a Live
  run.
* **Turning the workflow off kills its pending links.** Disabling a workflow stops it
  everywhere: no new run starts, and no waiting run resumes. Any approval links already out
  in people's inboxes stop working from that moment, they get the same "not found" as an
  expired one, and the waiting runs are marked failed with `workflow_disabled` so your run
  history says why. Turning the workflow back on does not revive them — a decision made
  about a workflow that was switched off is not a decision we will act on. If you need the
  approval, re-run the workflow once it is enabled again.

<Note>
  Resume links spend the same per-workspace execution budget as every other way of starting
  or continuing a run. A burst of resumes is rate-limited exactly as a burst of executions
  is.
</Note>

## Inside a loop

A Wait step works inside a **For each** loop as long as the loop runs one item at a time
(batch size 1). The loop stops on the item it is on, and resumes on that same item with
everything it has already collected intact.

A loop set to run items in parallel cannot pause — there would be several half-finished
items and no single place to record them — so a Wait step inside one fails with a message
saying to set the batch size to 1.

## What the run history shows

The step appears as **waiting** while it is paused, and completes when the answer arrives.
The completed step records who answered and what they said. It never records the link —
that is the point of storing only a hash.

## Limits

|                    |                     |
| ------------------ | ------------------- |
| Wait length        | 1 minute to 30 days |
| Approvers per step | 20                  |
| Callback payload   | 64 KB               |
| Comment            | 1,000 characters    |
| Message            | 2,000 characters    |
| Link uses          | 1                   |

## Related

* [Creating workflows](/workflows/creating-workflows)
* [Respond to Webhook](/workflows/respond-to-webhook) — answer an HTTP caller from a run
* [Storage](/workflows/storage) — state that outlives a single run
