# Approvals

A live agent key can't send a document. It can only ask. A named person approves the exact draft, and the server holds the line whatever the agent was told.

## The flow

1. The agent calls `create_document`. It gets a `draft_hash` and a `review_url`. Nothing is sent.
2. The agent calls `send_document` with the `id` and `draft_hash`.
3. The server compares the hash to the draft. If they differ, it refuses with `draft_changed`.
4. The document moves to `pending_approval`. The reply has an `approval_url` and nothing is sent. The account owner is told by email, and the `approval.requested` webhook fires.
5. A person signs in, opens the link and reads the draft as the server holds it.
6. They approve, and the server sends it. Or they reject, and it goes back to being a draft.
7. The agent reads the outcome with `get_document`, or waits for `approval.approved`.

## What the hash covers

The `draft_hash` covers the PDF bytes, the title, the message, the signing order, the disclosure setting, every signer's name and email, and every field. Change any of them and the hash changes. Approving a hash approves exactly that. If the draft changed after the request, the approval is refused.

## Who counts as an agent

| How the call arrives | Treated as |
|---|---|
| Over MCP, any key | Agent |
| REST, key set to "Needs my approval" | Agent |
| REST, key set to "Drafts only" | Agent. It can't even ask: `send_not_allowed` |
| REST, key set to "Sends directly" | Your own server. Sends at once |

A "Sends directly" key is for code you wrote and control. Don't give one to an agent. If you connect it over MCP, it is treated as an agent anyway.

## What approval looks like

Approval needs a signed-in person on the account. There is no approve call in the API, so no key can approve its own request. A request lasts 24 hours. The approver's identity and the hash go into the evidence log, next to the key that asked. The record keeps the agent and the person apart.

## What this doesn't stop

We prefer plain limits to big claims. An approver can still approve a bad draft, so read it. A person with a "Sends directly" key can hand it to an agent over REST. And an agent with full access to a signer's inbox could open that signer's link. We block signing by credential and make every step show in the record, but we can't reach inside someone's mailbox. For a high-value document, add an `access_code` and share it outside email.

## Test mode

Approval works the same in test mode, so you see the step before going live: the approval page carries a TEST banner. For CI and agent evals, `simulate_approval` approves a test draft without a person. It never works on a live document. See [test mode](/docs/test-mode).

## Common questions

### Can a person approve from the API?

No. Approval happens only on the signed-in page. If a key could approve, an agent holding that key could approve itself.

### What happens if nobody approves in 24 hours?

The request lapses and nothing is sent. It can no longer be approved. A person can open it and reject it, which returns the document to a draft, and then the agent can ask again.

### Can I let trusted automation skip approval?

Yes, over REST. Use a key set to "Sends directly" for code you control, such as a server sending a fixed template. Agents and MCP clients can't skip it.
