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

# Murph confirmations

> Handle explicit approval for Murph durable-write actions

Murph can propose durable writes while helping operate a storefront, such as
filing a report, updating operating instructions, publishing storefront setup
state, or changing other persistent configuration. For protected writes, Murph
returns a structured confirmation request instead of executing the write
immediately.

Clients should render the confirmation as an explicit approve/cancel control.
The control exists only when the response contains a structured pending
confirmation; assistant prose cannot create one. For report and integration
requests, Murph uses this staged control as the filing offer, and no team-visible
report exists until the approved replay succeeds.
On Murph UI-control surfaces, an ordinary-language reply that clearly approves
the action—such as "yes", "yep", "sounds good", or an equivalent in the user's
language—is also accepted for the exact pending action. Murph interprets the
reply semantically; ambiguous, conditional, or conflicting replies do not
execute. Phrase-token API/MCP flows still require the exact confirmation phrase.

## Confirmation lifecycle

1. Send a normal Murph chat request.
2. If the response includes `pendingConfirmations` (or `pendingConfirmation`),
   show the proposed action and an approve/cancel control for each entry.
3. POST each user decision to the confirmation decision endpoint.
4. If the user confirms, the response is a normal Murph chat response for the
   turn that executed the approved write.
5. If the user cancels, the response only records the cancelled confirmation.

<Note>
  **Prefer `pendingConfirmations` (plural).** Murph can propose multiple gated
  writes in a single turn (e.g. queue N `delete_campaign` calls). Older clients
  that only read `pendingConfirmation` (singular) render just the first widget
  and silently drop the rest. New clients should iterate `pendingConfirmations`
  and render one approve/cancel control per entry; each entry has its own
  `confirmationUid` and is decided independently.
</Note>

<Warning>
  `confirmationUid` is short-lived, single-use, and bound to the authenticated
  actor, conversation, tool, and resolved parameters. Do not persist it as a
  long-term approval record.
</Warning>

## Chat response fields

`POST /api/v2/murph/chat` and `POST /api/v2/murph/chat/stream` can return
two related fields on a turn where one or more protected writes were
proposed but did not run:

* **`pendingConfirmations`** *(array, new)* — every pending confirmation
  issued this turn, in tool-call order. Render one approve/cancel control
  per entry. Empty (or omitted) when nothing gated this turn. **New
  callers should prefer this field.**
* **`pendingConfirmation`** *(object, retained)* — the first entry from
  `pendingConfirmations`, or `null`. Kept for back-compat with clients
  that render at most one confirmation per turn (Slack, older SDKs). A
  client that reads only this field will silently drop the remaining
  N-1 controls when Murph gates multiple writes in one turn.

```json theme={null}
{
  "data": {
    "conversationUid": "6e60d909-721e-41ca-85b8-4e5a72bbf792",
    "answer": "This action needs approval before it runs.",
    "toolsUsed": [],
    "escalated": false,
    "escalation": null,
    "customerSwitch": null,
    "pendingConfirmation": {
      "confirmationUid": "50669fad-52e1-43c8-9334-77bf14ba72eb",
      "toolName": "report_issue",
      "toolKey": "report_issue",
      "summary": "Run `report_issue`.",
      "policy": "always",
      "resolvedParams": {
        "title": "Checkout page error",
        "severity": "low"
      },
      "writeExecuted": false,
      "plainAffirmativeAccepted": true,
      "expiresAt": "2026-06-13T19:45:00.000Z"
    },
    "pendingConfirmations": [
      {
        "confirmationUid": "50669fad-52e1-43c8-9334-77bf14ba72eb",
        "toolName": "report_issue",
        "toolKey": "report_issue",
        "summary": "Run `report_issue`.",
        "policy": "always",
        "resolvedParams": {
          "title": "Checkout page error",
          "severity": "low"
        },
        "writeExecuted": false,
        "plainAffirmativeAccepted": true,
        "expiresAt": "2026-06-13T19:45:00.000Z"
      }
    ]
  }
}
```

Each entry (in either field) uses this shape:

| Field                      | Type                      | Notes                                                                                                                                                                                     |
| -------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `confirmationUid`          | UUID                      | Pass this to the decision endpoint. Each pending confirmation gets its own UID; a multi-write turn yields N distinct UIDs.                                                                |
| `toolName`                 | string                    | Internal Murph tool that requested the write.                                                                                                                                             |
| `toolKey`                  | string                    | Stable key for the gated action.                                                                                                                                                          |
| `summary`                  | string                    | Human-readable action summary for the confirmation UI.                                                                                                                                    |
| `policy`                   | `"always"` or `"tainted"` | Why the confirmation gate applied.                                                                                                                                                        |
| `resolvedParams`           | object                    | Parameters the user is approving.                                                                                                                                                         |
| `writeExecuted`            | `false`                   | The write did not run on this turn.                                                                                                                                                       |
| `plainAffirmativeAccepted` | boolean                   | When `true`, a semantically clear ordinary-language approval can redeem this exact pending UI action; ambiguous or conflicting replies do not execute. Phrase-token flows remain `false`. |
| `expiresAt`                | datetime                  | Confirmation expiry time.                                                                                                                                                                 |

## Confirm or cancel

`POST /api/v2/murph/confirmations/{confirmationUid}/decision`

```bash theme={null}
curl -X POST "https://api.interchange.io/api/v2/murph/confirmations/50669fad-52e1-43c8-9334-77bf14ba72eb/decision" \
  -H "Authorization: Bearer $SCOPE3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "decision": "confirm" }'
```

## Request body

| Field      | Type                      | Required | Notes                                  |
| ---------- | ------------------------- | -------- | -------------------------------------- |
| `decision` | `"confirm"` or `"cancel"` | Yes      | Confirms or cancels the pending write. |

## Confirm response

When `decision` is `confirm`, the endpoint returns the same shape as a Murph
chat response. The approved write may appear in `toolsUsed`, and fields such as
`escalated` or `customerSwitch` reflect the write that actually ran.

```json theme={null}
{
  "data": {
    "conversationUid": "6e60d909-721e-41ca-85b8-4e5a72bbf792",
    "answer": "Filed the report.",
    "toolsUsed": [
      {
        "name": "report_issue",
        "input": {
          "title": "Checkout page error",
          "severity": "low"
        },
        "output": "{ \"status\": \"filed\" }",
        "isError": false
      }
    ],
    "escalated": true,
    "escalation": null,
    "customerSwitch": null,
    "pendingConfirmation": null
  }
}
```

## Cancel response

When `decision` is `cancel`, no write runs and the response only records the
cancelled confirmation.

```json theme={null}
{
  "data": {
    "confirmationUid": "50669fad-52e1-43c8-9334-77bf14ba72eb",
    "status": "cancelled"
  }
}
```

## Errors

* `400 VALIDATION_ERROR` - the path or request body is malformed.
* `404 NOT_FOUND` - the confirmation is unknown, expired, cancelled, or already
  used.
* `403 FORBIDDEN` - the confirmation belongs to another actor or account.
* `503 SERVICE_UNAVAILABLE` - Murph is not available to process a confirmed
  write.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Ask Murph" href="/v2/setup/ask-murph" icon="sparkles">
    Use Murph to operate and troubleshoot your storefront.
  </Card>

  <Card title="Authentication" href="/v2/authentication" icon="key">
    Authenticate Murph API requests.
  </Card>
</CardGroup>
