# Two-step confirmations (/en/docs/mcp/confirmaciones)

## The default: direct execution [#the-default-direct-execution]

When an agent calls `emit_document`, it emits.

Facturia does not interpose an approval step of its own, because the MCP client's tool-approval UI —
the thing that shows you "Claude wants to call `emit_document`, allow?" — **is** the human in the
loop. Adding a second Facturia-side confirmation on top of that, for every write, would be redundant
on the vast majority of calls and would defeat half the point of an agent interface.

## Where that is not enough [#where-that-is-not-enough]

There are two distinct failure modes, and the client's approval only solves one:

**The agent tries to do something the person did not ask for.** The client's own approval step
solves it — that is exactly what it exists for.

**The person reflexively approves everything their chat client asks them, and something with real
financial consequence — filing a tax return, an irreversible claim — goes out because someone
clicked "allow" on autopilot and not because they deliberately reviewed that figure.**
The client's approval does **not** solve this: it is the same click in both cases.

`require_confirmation` attacks the second.

## Turning it on [#turning-it-on]

It is a per-empresa flag in `automation_settings`, next to `auto_emit_46` and friends. It ships
**off**, like every automation.

```bash
curl -X PATCH https://api.facturia.cl/v1/empresas/emp_01K2R6.../automation_settings \
  -H "Authorization: Bearer $FACTURIA_KEY" -H "Content-Type: application/json" \
  -d '{"require_confirmation": true}'
```

It is a REST field, not an MCP-only setting: REST callers and the dashboard see and control the same
flag. The REST API described in the rest of these docs does not change behavior because you turned
it on.

## Which tools it covers [#which-tools-it-covers]

`emit_document`, `file_f29`, `emit_tipo46` and `reclaim_received_document` — the "emit / file /
claim" set.

Every other write (`accept_received_document`, for instance) stays direct even with the flag on:
accepting already matches the legal default that silence would produce anyway, so putting a lock on
it protects nothing.

## What it looks like [#what-it-looks-like]

```jsonc
// → file_f29
{ "empresa": "77928532-4", "period": "2026-07", "confirm_total_payable": 1373000 }

// ← pending_confirmation (la empresa tiene require_confirmation: true)
{
  "status": "pending_confirmation",
  "confirmation_id": "conf_01K2SD3P7Q",
  "confirmation_url": "https://app.facturia.cl/aprobar/conf_01K2SD3P7Q?token=mcpapv_9lQpV3fA…",
  "action": "file_f29",
  "summary": "File F29 for período 2026-07 — CLP 1.373.000 payable, due 2026-08-20.",
  "expires_at": "2026-08-14T14:45:00Z"
}
```

Nothing was filed. The agent hands you the summary and the link, and stops there.

## Who completes it: you, on a page [#who-completes-it-you-on-a-page]

You open `confirmation_url`, see which empresa, which action and with what figure, and press
**Confirm** or **Reject**. No sign-in needed: the link carries a single-use token, valid for those 15
minutes and for that action and no other. Only then is the F29 (Chile's monthly VAT return) filed —
with exactly the data that was summarized when the agent proposed it, not with whatever the world
looks like at that moment.

> **The agent cannot complete it, and that is the point**
>
> There is no MCP tool that closes a pending action. There was one — `confirm_action` — and it was
> withdrawn: if the agent can complete it by saying "the user told me yes", then the record of your
> approval is the agent's word for it, which is exactly what this flag exists to refuse. If you tell
> the agent you already approved, have it verify by reading (`get_document_status`, or `file_f29` with
> a `filing_id`).

Confirming twice replays the original result instead of executing twice — the same guarantee
`Idempotency-Key` gives a REST caller. Rejecting twice is not an error either: you wanted it not to
happen, and it is not happening.

An approval expires after **15 minutes** unclaimed. Once expired, the page says so and the agent has
to propose the action again to mint a new one.

## Sandbox: this is where you rehearse it [#sandbox-this-is-where-you-rehearse-it]

The two-step **works the same in sandbox**: turn `require_confirmation` on for a test empresa and the
emission is parked, the link is minted, and the `/aprobar` page opens exactly as it does live —
marked as a test, so nobody mistakes the rehearsal for the real thing.

> **This could not be rehearsed before**
>
> Until September 2026 the sandbox ignored the flag: the API accepted it, reported it as on, and
> emitted directly anyway. Which meant the most consequential bridge in the product — the one where an
> agent hands a decision to a person — could only be seen for the first time with real documents. Now
> it can be exercised at zero risk.
>
> The sixty-second demo is unchanged: the flag defaults to **off**, so a freshly created sandbox
> empresa still issues in a single call.

## The states that are not errors [#the-states-that-are-not-errors]

Two behaviors of this layer worth being clear about in the client:

* **A rate limit and a pending confirmation are not failures.** The equivalent of a `429` and the
  `pending_confirmation` responses are ordinary tool *results* with a clear `status` field, not
  thrown errors. An agent should read them and decide what to say next, not treat them as something
  broken.
* **Every tool description declares its own likely failure modes.** An agent choosing between
  `emit_document` and `draft_document`, or deciding whether it is safe to retry after a
  `sii_error`, should never have to consult external documentation mid-conversation. That is why
  `retriable` travels with every rejection reason.
