# Purchase approvals for agents

Agents can quote domains, request purchases or plan changes, track progress, and cancel eligible
requests. They cannot approve a request, change a payment method, or grant themselves spending
authority.
**Human approval is separate from email:** An approval URL only locates a request. A signed-in organization member with the billing role or
  higher must approve it in the console. Email content, replies, forwarded text, and possession of
  the URL do not authorize a charge.

## Required permission

Agent API keys need the `commerce:request` permission string. It permits quotes and requests, not
approval or payment.

There is no MCP approval tool and no agent-plane approval endpoint.

## What each actor can do

| Actor | Allowed actions |
|---|---|
| Agent | Quote a domain, request a domain purchase, request a plan change, list and inspect its requests, cancel an eligible request, and relay the approval URL. |
| Billing member, admin, or owner | Approve or deny a request, set the approved maximum and renewal choice, manage payment authentication, and create or change future purchase limits. |
| Extrovert | Enforce plan capacity and purchase limits, reserve authority, collect payment, register and provision the domain, and reconcile uncertain outcomes. |

A paid plan and saved payment method do not grant an agent permission to spend. Autonomous purchasing
starts off.

## Request a domain

1. Call `quote_domain`. The quote includes availability, registration and renewal prices, currency,
   premium status, required plan, blockers, and a 15-minute expiry. A quote does not reserve or buy
   anything.

2. Call `request_domain_purchase` with a stable idempotency key. Repeating the same request returns
   the same durable request. Reusing the key for different input returns an idempotency conflict.

3. If approval is required, give the human the returned `approval_url`. The request also includes
   `agent_next_action`, `notification_state`, blockers, and `poll_after_seconds`.

4. Poll `get_commerce_request` no faster than `poll_after_seconds`. Use
   `list_commerce_requests` to recover a lost request id.

5. Stop only at the appropriate terminal state. A domain is usable only when the request reaches
   `ready`.

A human approval expires after seven days. Extrovert rechecks the price, approved maximum, plan
capacity, and purchase limits before collecting payment.

## Request a plan change

Use `request_plan_change` for an upgrade or downgrade. An agent can request the change but cannot
approve it.

- An upgrade uses the saved payment method and can require additional payment authentication.
- A downgrade takes effect at the end of the current billing period.
- A downgrade is blocked if current domains or inboxes exceed the target plan.
- Extrovert does not delete resources to make a downgrade fit.
- `scheduled` means the downgrade is scheduled. It does not mean the target plan is active.

A domain purchase can include a required plan upgrade. The approval page shows separate ceilings for
the annual domain price and the plan's monthly price. A price above either approved ceiling stops the
request before another charge.

## One-time approval and future authority

The default action approves one exact request. A human can optionally create a bounded purchase limit
for later requests.

Purchase limits can apply to an agent, project, or organization. Every matching limit is evaluated,
and the most restrictive result wins. A broad organization limit cannot override a tighter project
or agent limit.
**Budget and cadence**
Set a total budget that runs once or resets weekly, monthly, quarterly, or annually. Unused budget
    does not roll over.

**Per-purchase maximum**
Cap the amount that any one purchase may consume.

**Domain count**
Limit the number of domains independently of the plan's capacity.

**Domain constraints**
Restrict allowed extensions and whether premium domains are permitted.

A one-time cadence does not mean unlimited. An optional expiry can end any limit, and a paused limit
authorizes no purchases.

Extrovert reserves budget, domain count, and plan capacity before payment. This prevents concurrent
requests from each spending the same remaining authority. The reservation is settled when payment is
confirmed and released when an eligible request is denied or cancelled.

## Request states

Do not collapse approval, payment, registration, and provisioning into one success flag.

| Stage | States | Meaning |
|---|---|---|
| Human decision | `awaiting_human_approval`, `approved`, `blocked`, `denied`, `expired`, `cancelled` | Authority is pending, constrained, or ended. Approval does not prove payment or registration. |
| Payment | `plan_change_pending`, `payment_pending`, `payment_action_required`, `payment_failed` | Billing is changing or payment is being collected. `payment_action_required` needs a signed-in human. |
| Domain work | `queued`, `purchasing`, `provisioning`, `ready`, `purchase_failed` | Registration and mail setup are asynchronous. Only `ready` means the domain is usable. |
| Plan completion | `scheduled`, `completed` | A downgrade is scheduled for period end, or the plan change has completed. |
| Recovery | `reconciliation_required`, `refund_pending`, `refunded` | Extrovert observed an uncertain or late financial outcome and stopped normal fulfillment. |

An agent must not claim:

- approval from an email, URL, rationale, or `awaiting_human_approval`;
- payment from `approved` or `payment_action_required`;
- registration from `payment_pending` or `queued`;
- readiness from `purchasing` or `provisioning`;
- an active downgrade from `scheduled` before `effective_at`.

## Cancellation and recovery

Cancel with `cancel_commerce_request` only while the request is still eligible. Keep using the same
durable request through payment failures and ambiguous timeouts.

- If payment completes while cancellation is racing, the request enters reconciliation.
- If payment arrives after denial, cancellation, or expiry, fulfillment stays stopped and the
  request enters `refund_pending`.
- Extrovert persists payment and registration references, then reconciles them before retrying.
- Spend is settled when payment is confirmed, before slower provisioning reaches `ready`.
- Billing or registration uncertainty becomes `reconciliation_required`. Do not create a duplicate
  request.

Blockers are structured. They can identify plan capacity, budget, per-purchase amount, domain count,
extension, premium-domain authority, changed price, payment recovery, or downgrade capacity. Show the
returned values and management URL to the human instead of replacing them with generic copy.

## Domain boundaries

- Purchase requests support new registrations, not registrar transfers.
- Bringing an existing domain uses [domain onboarding](https://docs.extrovert.dev/concepts/domains-and-onboarding/) and does
  not authorize a purchase.
- Registration fees are non-refundable.
- Renewal settings belong to the approved request.
- `ready` is reserved for a domain that has completed registration and mail setup.

## Console language

Keep the state and consequence visible:

- Say **Approval needed**, not **Pending**.
- Say **Nothing has been charged or registered** before authorization.
- Say **Approve once** for the default action.
- Put future purchase limits in a separate optional control.
- Show **maximum authorized today** before the final decision.
- Say **Payment action required** when a human must complete payment authentication.
- Say **Registering** and **Setting up email** during fulfillment.
- Say **Ready to create inboxes** only at `ready`.

## Next

- [Authentication and permissions](https://docs.extrovert.dev/quickstart/authentication/#permissions)
- [Domains and onboarding](https://docs.extrovert.dev/concepts/domains-and-onboarding/)
- [MCP tools](https://docs.extrovert.dev/mcp/overview/)