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

# Confirmations

> Some writes stop and ask before they happen. The run pauses, you approve or reject, and Patchwork performs the write only if you said yes.

A patch can be marked as always requiring approval. When the agent decides to call one, the runtime does not execute it. It records the intended call, pauses the run, and waits for a decision.

This is the gate that makes an agent safe to point at real operations. Nothing has happened yet when you are asked — the write runs only after you approve.

```
agent decides to call a gated patch
        ↓
runtime records the call, does not execute
        ↓
run pauses in awaiting_input
        ↓
you approve ─────▶ Patchwork performs the write ─▶ run continues
you reject  ─────▶ the model is told it was declined ─▶ run continues
```

## Finding a pending confirmation

The run pauses in `awaiting_input` — the same state as a question. To tell them apart, read `pending_confirmation` from `GET /v1/loom/threads`:

```json theme={null}
{
  "pending_confirmation": {
    "run_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "tool_call_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "patch_ref": "send_payment@3",
    "summary": { "title": "Send 50 USDC to Jane", "fields": { "amount": "50 USDC", "to": "Jane Doe" } },
    "risk": "high"
  }
}
```

`summary` is built for exactly this purpose — render it as the approval prompt rather than showing raw arguments. `risk` is the effective risk level after any agent-level overrides, and is a reasonable input to how prominent you make the confirmation.

If you use [realtime](/api-reference/realtime), the `write.confirmation_requested` event carries the same `tool_call_id`, `patch_ref`, `summary`, and `risk` the moment the run pauses.

## Approving

```bash theme={null}
curl -X POST https://api.usepatchwork.co/v1/loom/runs/<run_id>/confirm \
  -H "Authorization: Bearer sk_live_..." \
  -H "Patchwork-Subject: user_9f2:ws_acme" \
  -H "Content-Type: application/json" \
  -d '{
    "tool_call_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "decision": "approve"
  }'
```

```json theme={null}
{ "run_id": "7c9e6679-…", "state": "running" }
```

The response is `202`. Patchwork performs the write server-side, records the result on the tool call, and resumes the model loop so the agent can report back. Poll the run or wait for `run.completed`.

## Rejecting

```bash theme={null}
  -d '{
    "tool_call_id": "9b1deb4d-…",
    "decision": "reject",
    "detail": { "reason": "Wrong recipient" }
  }'
```

Nothing is executed. The model is told the call was declined, and the run resumes so the agent can respond — usually by asking what to do instead. `detail` is optional, recorded on the tool call, and passed to the model, so a short reason produces a better next turn than a bare rejection.

## When an approved write fails

Approval is permission, not a guarantee. If the write is attempted and your endpoint errors, the run does not fail — the error is handed to the model so it can explain what happened, and the tool call is recorded with status `failed`.

Your `POST /confirm` still returns `202`. Check the run's outcome, or the trace, to see whether the write actually succeeded.

## Do not post a message instead

While a confirmation is pending, posting a message to the thread is rejected:

```json theme={null}
{
  "status": "error",
  "error": {
    "message": "This run is waiting for you to approve or reject a pending change.",
    "code": "awaiting_confirmation"
  }
}
```

Resolve the confirmation first. The run resumes on its own afterwards.

## Errors

| Code | Status | When |
| - | - | - |
| `unknown_confirmation` | `404` | No pending gated call with that `tool_call_id` on that run. |
| `not_awaiting_confirmation` | `422` | The run is not paused at a gate. |
| `invalid_decision` | `422` | `decision` was not `approve` or `reject`. |
| `awaiting_confirmation` | `422` | You posted a message while a decision was pending. |

A confirmation can only be resolved once. A second call for the same `tool_call_id` returns `unknown_confirmation`, because the call is no longer pending.

## Not the same as an outcome

A confirmation is permission to act. An [outcome](/api-reference/run) reports an action you already took. See [Runs and states](/guides/runs#confirm-versus-outcome) for the full comparison.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.