# How do I require quote-bound approval before an agent payment settles?

**Short answer:** Do not let an agent settle from a shared treasury on a vague "buy it" yes. Give it a dedicated wallet or card with narrow instrument limits, require a human approval bound to the exact quote (amount, currency, payee/merchant, quote_id or cart hash), re-verify that hash immediately before capture or broadcast, and write the allow/deny to storage the agent cannot edit. Stripe Issuing for agents supports per-card spend controls and real-time issuing_authorization.request checks (respond within about 2 seconds) so you can confirm amount and merchant against the approved quote before the charge lands. Caps in the prompt are not a settlement gate; set_spend_policy plus request_human_approval plus an outside-agent record are.

## Checklist
1. Issue a dedicated card or wallet per agent (or per high-risk workflow). Fund only what that workflow may spend; never hand over the company treasury key.
2. Set instrument-level ceilings first (per-authorization and period caps, allowed merchants/categories). Stripe Issuing spending_controls and wallet signing policies reject over-cap attempts even if the model forgets the prompt.
3. When a vendor returns a quote or 402/price, freeze quote_id (or cart hash), amount_minor, currency, payee, and expiry into server storage the agent cannot UPDATE.
4. Call request_human_approval with those exact fields in action. Show the approver the quote fields from the payment request, not the model's paraphrase.
5. Before settlement: verify_human_approval against the live quote hash; run authorize_spend (or your issuer's real-time auth) against set_spend_policy; refuse if amount, payee, or quote_id drifted.
6. Settle only after both checks pass. Use an idempotency key so a resumed or retried run cannot pay the same quote twice.
7. Append every approve, deny, timeout, and settlement receipt outside the agent session (ledger or server DB). Keep only receipt ids in chat memory.
8. Expire stale quotes and approvals; a yes for quote Q1 is not a warrant for Q2 after a price change.

## Dedicated wallet, narrow limits, then a quote-bound yes
- A shared corporate card with "ask before big purchases" in the system prompt fails open under prompt injection or a hurried alwaysApprove. Isolate funds and enforce ceilings on the instrument.
- Stripe Issuing for agents documents spend controls at card creation (and updates later), plus real-time authorization so your code can approve or decline from task context — including amount confirmation against the expected budget for the order — before the charge lands.
- set_spend_policy on a Rightshold credential sets per_tx_max_minor, daily_max_minor, allowed_domains/categories, and optional expires_at. authorize_spend returns a signed allow/deny against that policy; it records decisions only and never moves money.
- The human yes is a third layer: bind it to quote_id, amount_minor, currency, and payee so a higher requote or a swapped merchant needs a new approval.

## Re-check the quote at settlement, not only at ask time
- Prices move. Between approval and capture the vendor may return a new total, a different token, or another payTo address. Re-hash the live quote and compare to the approved action; on mismatch, fail closed and open a new request_human_approval.
- OpenAI's Agents SDK keeps approval state on the server for browser/mobile UIs; do not treat a client-uploaded RunState or an agent-written approved_quote.json as authorization.
- Stripe's issuing_authorization.request path is for code checks you already prepared (approved quote hash, task budget), not for paging a human inside the ~2 second window — get the quote-bound yes first, then let settlement run under that grant.
- Write allow/deny and the settlement reference to append-only storage. How to gate an agent wallet or card with per-task caps covers task budgets and revoke; this page is specifically about binding the yes to one quote before money moves.

## What can go wrong?
- Approval screen shows "about $40 for supplies" while the quote is 42.17 USD to a different merchant legal name.
- Quote expires or is replaced; the agent reuses the old approval id because nothing compared quote_id or amount_minor at capture.
- Real-time auth times out and the card's default is approve; for agent cards, configure timeout to decline and keep the webhook fast.
- Settlement CSV lives in the workspace where the agent can delete the deny row after a bad payment.

## Ask Rightshold (free, no key)
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code (one-click setup: https://www.rightshold.com/start?ref=seo), then ask: "Before this agent settles, set a narrow spend policy on its credential and ask me to approve the exact quote (quote id, payee, amount and currency)."

```json
{
  "tool": "set_spend_policy",
  "arguments": {
    "credential_id": "crd_…",
    "currency": "USD",
    "per_tx_max_minor": 5000,
    "daily_max_minor": 15000,
    "allowed_domains": [
      "api.vendor.example"
    ],
    "allowed_categories": [
      "saas"
    ],
    "expires_at": "2026-11-07T00:00:00Z"
  }
}
```
- Needs your API key (owner). set_spend_policy replaces the previous policy; every version stays on the ledger. authorize_spend then returns a signed allow/deny for each purchase (records only; never moves money).
- Next, request_human_approval with action { quote_id, amount_minor, currency, payee, cart_hash }. verify_human_approval fails if those fields changed after the yes.
- Re-check the live quote hash immediately before capture or broadcast; expire stale quotes and approvals.
- How to require human approval before an AI agent spends money and How to gate an agent wallet or card with per-task caps cover the general approval pattern and instrument/task caps.

_Rightshold records spending policies, spend authorizations and human approvals for agents that call it. It does not issue cards, hold balances, sign chain transactions, sit in your Stripe webhook, or stop an agent that never asks. Enforce quote checks on the card/wallet and in your settlement path too. Not legal advice._

## Sources
- [Stripe Docs: Issuing for agents (spend controls; real-time authorization; amount confirmation)](https://docs.stripe.com/issuing/agents)
- [Stripe Docs: Issuing spending controls (per_authorization and period limits)](https://docs.stripe.com/issuing/controls/spending-controls)
- [Stripe Docs: Issuing real-time authorizations (issuing_authorization.request; respond within 2 seconds)](https://docs.stripe.com/issuing/controls/real-time-authorizations)
- [OpenAI Agents SDK (JS): Human-in-the-loop (keep approval state on the server)](https://openai.github.io/openai-agents-js/guides/human-in-the-loop/)
- [Agent spending policies on Rightshold](https://www.rightshold.com/agent-spending-policies)
- [Human approvals on Rightshold](https://www.rightshold.com/human-approvals)

## Related
- [How to gate an agent wallet or card with per-task caps and an outside-agent spend record](https://www.rightshold.com/answers/how-to-gate-an-agent-wallet-or-card-with-per-task-caps-and-an-outside-agent-spend-record)
- [How to require human approval before an AI agent spends money](https://www.rightshold.com/answers/how-to-require-human-approval-before-an-ai-agent-spends-money)
- [How to stop an AI agent from paying twice when it retries](https://www.rightshold.com/answers/how-to-stop-an-ai-agent-from-paying-twice-when-it-retries)
- [How to keep an agent risk/approval record outside the agent's editable session](https://www.rightshold.com/answers/how-to-keep-an-agent-risk-approval-record-outside-the-agents-editable-session)

_Not legal advice. Updated 2026-11-06. JSON: https://www.rightshold.com/answers/how-to-require-quote-bound-approval-before-an-agent-payment-settles.json_