> For the complete documentation index, see [llms.txt](https://docs.doma.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.doma.xyz/agentic-commerce/mcp-server/authorization.md).

# Authorization & Spend Controls

The read tools need nothing. The execute tools — buying a listed domain, swapping tokens — sign and broadcast real transactions from your Doma wallet, so they sit behind an authorization step and a spend budget you control.

This page is the user-facing model. For the architecture underneath it, see [Agentic Wallet](/agentic-commerce/agentic-wallet.md).

## Authorize once

The first time an agent calls an execute tool without a token, the server answers with a standard OAuth challenge instead of an error. Your MCP client turns that into a browser flow:

{% stepper %}
{% step %}

### The client starts the flow

Your MCP client registers itself and opens the Doma consent page in your browser. In Claude Code this is what `/mcp` triggers; hosted clients like Claude do it inline when a tool needs it.
{% endstep %}

{% step %}

### You sign in and set a budget

You sign in to Doma with your existing account, pick the wallet the agent will act from, enter a USD spending budget (default `$200`), and review exactly what you're approving:

* Trade on Doma chains only
* Cannot transfer your funds to outside addresses
* Spend up to the budget you entered
* When the budget is used, you'll be asked to refill
* Until you revoke
  {% endstep %}

{% step %}

### The agent gets a scoped session

Approving mints a session bound to that one wallet, that one network, and that one spend allowance. From then on the agent can execute within the budget without asking again.
{% endstep %}
{% endstepper %}

Authorization is **per network**. A session on testnet grants nothing on mainnet, and vice versa.

## What the agent can and cannot do

The agent **never holds your private key**. The key stays inside Privy's HSM (see [Agentic Wallet](/agentic-commerce/agentic-wallet.md)); the agent holds a delegated authorization that Privy enforces a policy against, and Doma's own spend ledger gates every call on top of that.

**Can:** buy listed domains, swap tokens, bridge assets out to other chains, place and cancel limit orders, and read anything — on the Doma network you authorized, from the one wallet you approved, within the budget you set.

**Cannot:**

* Transfer your funds to an outside address.
* Act on any other chain.
* Grant an **arbitrary** ERC-20 approval — a standing approval hands out authority the USD budget can't bound, so a general approval is refused outright. Tools that need one for a single trade (swap, buy, bridge) batch it with the trade into one atomic operation. The **one** exception is the limit-order router approval — see [Limit orders](#limit-orders-a-separate-authority-track) below.
* Exceed the budget, the per-transaction ceiling, or the rate limit.
* Sell anything. Listing a domain and accepting an offer are not exposed as tools.

## The spend allowance

Every execution is priced in USD by simulating it, then charged against your allowance before it's broadcast. Reads are free and never touch it.

| Control                   | What it does                                                                           | Default                        |
| ------------------------- | -------------------------------------------------------------------------------------- | ------------------------------ |
| **Spend cap**             | Cumulative USD the agent may spend on this grant before it must be refilled            | `$200` — you set it at consent |
| **Per-transaction limit** | A single transaction above this is refused, even with budget remaining                 | `$250`                         |
| **Minimum charge**        | Floor charged per execution, so gasless writes that move no funds still consume budget | `$0.01`                        |
| **Rate limit**            | Maximum executions per allowance per window                                            | `30` per 60s                   |

{% hint style="warning" %}
The cap is a **budget, not an escrow**. It bounds what the agent can spend; it doesn't lock funds or guarantee a trade is favourable. Quote first (`marketplace.quote.v1`, `tokens.quote.v1`) and set a cap you'd be comfortable losing to a bad decision.
{% endhint %}

## Limit orders: a separate authority track

Limit orders sit outside the USD spend allowance, and it's worth understanding why. A limit order fills **off-session** — Doma's orders-worker executes the swap later, when the market reaches your price — so the spend happens at a moment the ledger can't simulate and charge ahead of time. Metering it at creation would mean reserving, then settling or refunding against fills the budget never sees.

Instead, a limit order is bounded by a **standing on-chain allowance** you grant to the DomaOrderRouter:

* **`defi.approveRouter.v1`** approves the router to pull one of your ERC-20 tokens up to an amount you choose — a shared pool the router draws down as your orders fill. This is the one standing ERC-20 approval the agent is allowed to make, and it's safe because the spender is fixed to the router Doma resolves server-side, never an address the agent supplies. Only the token and amount are yours to pick. The approval itself is a gasless on-chain operation, charged only the minimum floor (a grant moves no funds), and it counts against the rate limit and the audit trail like any other execution.
* **`defi.revokeRouter.v1`** zeroes that allowance. It's the kill switch for limit-order fills: existing `OPEN` orders stay, but none can fill until you re-approve.
* **`defi.limitOrder.create.v1` / `.cancel.v1`** only write the order record — they sign nothing and cost nothing against either budget.

So the amount you approve to the router **is** the ceiling on what limit orders can ever spend, independent of the USD cap. Set it to what you intend to trade, and revoke when you're done.

## Managing the allowance

Three tools let the agent — and therefore you, in plain language — manage the session:

| Tool                 | What it does                                                                           |
| -------------------- | -------------------------------------------------------------------------------------- |
| `agent.allowance.v1` | Report the wallet, network, cap, spent, remaining, and the limits in force. Read-only. |
| `agent.setCap.v1`    | **Lower** the cap. Lowering needs only the session; raising requires re-consent.       |
| `agent.revoke.v1`    | Kill switch — revoke the allowance so no further execution is authorized.              |

Just ask:

> How much budget does my Doma agent have left?

> Lower my Doma spend cap to $20.

> Revoke my Doma agent session.

**Refilling.** When the budget runs out, re-run the consent flow. Re-consenting while the grant is active tops up the same grant; re-consenting *after* a revoke opens a new grant with a fresh budget.

**Revoking completely.** `agent.revoke.v1` stops all further execution immediately. To also detach the agent signer from the wallet, do it from the Doma launchpad.

## Gasless execution

Executions on Doma chains are broadcast as **sponsored transactions** — no ETH needed on the Doma chain, and gas is never charged to your allowance; only the value the transaction moves is.

One consequence worth knowing: a successful call means the operation was **broadcast on-chain**. For writes a registrar or DNS layer then applies, that's not the same as the change being live — read the corresponding read tool back to confirm.

## When an execution is refused

Refusals come back as a structured result with a reason and your current budget view — not as a crash — so the agent can explain and adapt:

| Reason                                       | What happened                                                                                                 |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `allowance_exhausted` / `allowance_exceeded` | The budget is spent, or this transaction would exceed it. Refill by re-consenting.                            |
| `allowance_revoked`                          | The session was revoked. Re-authorize to get a new one.                                                       |
| `per_tx_limit_exceeded`                      | This one transaction is above the per-transaction ceiling.                                                    |
| `rate_limited`                               | Too many executions too fast. Wait for the window to roll over.                                               |
| `approval_not_permitted`                     | The transaction would grant an ERC-20 approval. Use the swap or buy tool instead.                             |
| `chain_not_supported`                        | The transaction targets a chain this server doesn't broadcast on.                                             |
| `router_unavailable`                         | No DomaOrderRouter is registered for this network, so a `defi.approveRouter.v1` grant had nothing to approve. |
| `simulation_failed`                          | The transaction wouldn't succeed on-chain, so it was never sent and nothing was charged.                      |

Every execute-tier outcome — broadcast or refused — is written to an append-only audit trail on Doma's side.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.doma.xyz/agentic-commerce/mcp-server/authorization.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
