Rightshold™ Sign up

Answers · agent safety

How do I enforce an AI agent's payment caps at the execution boundary instead of in the prompt, and record the approval details with each payment?

Last updated

TL;DR: A spending limit written in the system prompt is an instruction the model may follow, not a control: prompt injection, a long context or a confused plan can talk it past the number, and nothing stops the call. Put the cap at the execution boundary instead, the one place every payment has to pass: the pay tool's wrapper, a payment gateway or proxy in front of the wallet, or the card issuer's authorization step. That code reads the policy from storage the agent can't write, adds up what this task and this agent have already spent, checks the payee and amount, and refuses before any money moves. When a payment needs a person, the boundary checks that an approval exists for this exact amount, currency and payee and hasn't expired, then writes the approval details (approval id, approver, decided_at, policy id and version, action hash) onto the payment itself, for example as Stripe metadata, and into an append-only record. Then any payment can be traced to the rule and the person that allowed it without trusting the agent's own log.

What should I check, step by step?

1. Remove the cap from the prompt as the control. You can leave a sentence telling the model the budget so it plans well, but the number that matters lives in a policy store the agent's tools can only read.

  1. Find the boundary: the single function, proxy or issuer hook every payment must pass. If the agent holds a raw API key, card number or wallet key it can call around your wrapper, so give it a scoped credential that only works through the boundary.
  2. At the boundary, check in this order: policy exists and isn't expired, payee is allowed, amount is under the per-payment cap, amount plus spend already recorded for this task and this agent is under the task and period caps, and an approval is present if the amount is over the approval threshold.
  3. Count spend from your own record of authorized payments, not from what the agent says it has spent. Reserve the amount when you allow it and release it if the payment fails, so parallel calls can't each pass the same remaining budget.
  4. For approvals, compare a hash of the exact action (amount in minor units, currency, payee, item or quote id) with the hash the person approved, and check the approval's expiry. A different amount or payee is a different action.
  5. Write the approval details onto the payment: approval_id, approver, decided_at, policy_id, policy_version and action_hash. Stripe allows 50 metadata keys of up to 40 characters with values up to 500 characters, enough for ids and a hash; put anything bigger in your own store and reference its id.
  6. Write every allow and every deny, with its reason code, to storage the agent can't edit, and keep the same ids there so the payment and the decision can be joined later.
  7. Add an instrument-level limit as a backstop (card spending controls, a small dedicated wallet), so a bug in your boundary still can't spend the whole balance.

Why isn't a spending cap in the agent's prompt a real control?

OWASP's LLM01:2025 Prompt Injection entry describes inputs that change a model's behaviour in ways the developer didn't intend, including through content the agent reads such as web pages and documents. A spending rule held only in the prompt can be overridden the same way.

Where is the execution boundary for agent payments?

In your own code: the tool function the agent calls to pay. It's the simplest place, but only works if the agent has no other way to pay (no raw keys in the environment, no generic HTTP tool that can reach the payment API).

What approval details should be recorded with each agent payment?

On the payment object: approval_id, approver, decided_at, policy_id, policy_version, action_hash and the task id. Stripe copies PaymentIntent metadata to the Charge it creates as a one-time snapshot, and includes metadata in webhook events, so the details travel with the payment.

What are the common failure modes?

The cap is enforced in the tool wrapper, but the agent also has a shell or HTTP tool and the API key in an environment variable, so it pays around the wrapper.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Set a spending policy on this agent's credential so caps are checked at payment time, not in the prompt: per-payment and daily caps, allowed payees, and an expiry.”

One-click setup

{
  "tool": "set_spend_policy",
  "arguments": {
    "credential_id": "crd_…",
    "currency": "USD",
    "per_tx_max_minor": 2500,
    "daily_max_minor": 10000,
    "allowed_domains": [
      "api.vendor.example"
    ],
    "allowed_categories": [
      "saas"
    ],
    "expires_at": "2026-11-08T00:00:00Z"
  }
}

Rightshold doesn't hold payment credentials or process payments. It stores spend policies, returns signed allow/deny decisions and records human approvals that your own payment code checks. Not legal or financial advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'