Give the agent its own workspace identity, give that identity a monthly budget, and add an amount rule with a tx (per-transaction) window set to the dollar amount you want to be the hard per-payment ceiling. A rule evaluation engine then checks every payment request against the budget and the rule before anything is issued, and returns allowed, blocked, or pending_human instead of a yes/no guess. Below is a full walkthrough using a real policy engine (Pink Agentic AI Payments' public sandbox) so you can see the actual request and response bodies, not a diagram.
How the limits are layered
Pink checks three kinds of limit, in this order, before it issues anything: company breakers (agent paused, the agent's monthly budget used up, the company-wide daily ceiling hit, vault balance), then the rule list, top to bottom, first match wins, default is block. Rules carry an amount range and a window: tx (this payment alone), day or month (running total). A hard per-payment ceiling is a rule with window: "tx". The steps below set that up and run it.
Step 1: create a sandbox workspace
No signup form, just a POST. This returns an admin key for the company dashboard and one API key per seeded agent.
curl -X POST https://agentic-sandbox.pinkwallet.com/v1/sandbox/workspaces \
-H 'content-type: application/json' \
-d '{"company":"Acme Procurement Test","email":"you@example.com","template":"coffee"}'
The response includes a workspace_id, an admin_key, and a list of agents, each with its own key and MCP URL, for example https://agentic-sandbox.pinkwallet.com/mcp/<agent_key>. The "coffee" template seeds four agents (Purchasing, Inventory, Marketing, Payroll & Bills) with starter budgets and payees so you don't have to build fixtures by hand.
Step 2: give the agent a monthly budget
Every agent already has a monthly budget field. You can raise or lower it from the admin side:
curl -X PATCH https://agentic-sandbox.pinkwallet.com/v1/admin/agents/a_purch \
-H "Authorization: Bearer $ADMIN_KEY" -H 'content-type: application/json' \
-d '{"monthly":3000}'
Checking the agent's own view of its budget confirms the number is live:
{
"agent": "Purchasing AI",
"monthly_budget": 3000,
"spent_this_month": 2260,
"left_this_month": 740,
"single_payment_cap": 500,
"company_daily_ceiling": 6000
}
The response also shows a single_payment_cap field. In the current sandbox the engine does not check that field when deciding a payment, so set the per-payment ceiling with a rule, as in the next step.
Step 3: add a per-payment amount rule with window "tx"
The policy is a list of rules evaluated top to bottom, first match wins, default is block. To make a hard per-payment ceiling, add a rule with window: "tx" and no monthly or daily accumulation, just the single transaction amount:
curl -X PUT https://agentic-sandbox.pinkwallet.com/v1/admin/rules \
-H "Authorization: Bearer $ADMIN_KEY" -H 'content-type: application/json' \
-d '{
"rules": [
{
"id": "r_cap",
"name": "Hard per-payment cap: $150 (Purchasing AI)",
"agents": ["a_purch"],
"payee": "any",
"min": 150.01,
"max": null,
"window": "tx",
"action": "block"
}
]
}'
This rule has to sit ahead of any rule that would otherwise allow the same payee and agent for a larger amount, because the engine stops at the first match. Putting it first in the array achieves that.
Step 4: try an in-limit payment
Over REST (the same calls are exposed as MCP tools, pink.check_policy and pink.request_payment, for a client that connects over MCP):
curl -X POST https://agentic-sandbox.pinkwallet.com/v1/payments \
-H "Authorization: Bearer $AGENT_KEY" -H 'content-type: application/json' \
-d '{"payee_id":"p_sysco","amount":120,"currency":"USD","purpose":"Weekly milk and syrup reorder"}'
The actual response from this sandbox run:
{
"payment_id": "pay_bb13deacc29e",
"decision": "allowed",
"agent": "Purchasing AI",
"payee": "Sysco",
"amount": 120,
"rule": "Small supply orders go through",
"credential": {
"type": "virtual_card",
"sandbox": true,
"max_amount": 120,
"single_use": true,
"card": { "pan": "4111 1111 7298 7706", "exp": "12/27", "cvv": "843" }
}
}
$120 is under the $150 cap, so the new block rule skips, and an older allow rule for approved suppliers under $500 matches instead. A single-use virtual card number is issued for exactly $120.
Step 5: try an over-limit payment
Same agent, same payee, bigger amount:
curl -X POST https://agentic-sandbox.pinkwallet.com/v1/payments \
-H "Authorization: Bearer $AGENT_KEY" -H 'content-type: application/json' \
-d '{"payee_id":"p_sysco","amount":300,"currency":"USD","purpose":"Large milk and syrup reorder"}'
Response:
{
"payment_id": "pay_f0e7f8427aea",
"decision": "blocked",
"amount": 300,
"rule": "Hard per-payment cap: $150 (Purchasing AI)",
"credential": null,
"why": "matched · block"
}
$300 is well inside the agent's monthly budget (there was $740 left), and well inside the vault balance. It is blocked purely because the per-transaction rule matched before any allow rule had a chance to. No credential is issued. The dry-run endpoint, pink.check_policy / POST /v1/payments/check, returns the same decision with a full trace, step by step, without spending anything, useful when you want to show the agent (or a human) why a payment would fail before it tries.
A third outcome: held for a human
The same rule set also contains a rule that asks a human whenever the agent tries to pay a payee that isn't on the approved list, regardless of amount:
{
"decision": "pending_human",
"amount": 50,
"rule": "New payee: always ask the owner",
"hold_id": "pay_009dec96a998",
"approvers_needed": 1,
"who": "Maya Chen (Owner)",
"poll": "pink.get_credential(hold_id) · or GET /v1/payments/{id}"
}
The agent (or the MCP client driving it) polls that hold until a person approves or declines it. This is the third decision type, next to allowed and blocked: the payment is neither executed nor refused, it waits.
Pink Agentic AI Payments checks each agent's budget and amount rules at the MCP layer, before a payment executes.
What other approaches exist
-
Stripe's agent tooling: Stripe publishes an MCP server and an "Agents" surface (
docs.stripe.com/agents) built on top of Stripe Issuing, where spend controls (card-level limits, real-time authorization, restricted API keys) are enforced by Stripe Issuing when the card is authorized. If you already use Stripe Issuing, this is a reasonable starting point. See docs.stripe.com/agents and docs.stripe.com/mcp. - x402 (Coinbase): a protocol that uses the HTTP 402 status code so a server can ask for payment inline, settled in stablecoins on EVM-compatible chains or Solana, with no accounts or API keys. It's built for per-request micropayments rather than company-defined budgets per agent; spend limits aren't part of the base spec. See x402.org.
- AP2 (Google): an open protocol extension to Agent2Agent (A2A), currently at spec version 0.2, that defines "mandates" (cryptographically signed authorization objects) a human or policy can issue to constrain what an agent is allowed to buy. It's a specification for how parties talk to each other, not a hosted payments product you call. See ap2-protocol.org.
If your use case is "one AI client, connect once over MCP, get a per-agent budget and a per-payment rule enforced server-side before anything is issued," that's the shape this walkthrough covers. If you need live settlement in stablecoins today, or you're already deep in Stripe Issuing, the two links above are worth reading directly.
Try it
The sandbox above uses fake money and seeded templates, no card or bank details required to create a workspace. Try the full flow: agentic-sandbox.pinkwallet.com. Developer docs: pinkwallet.com/agentic/developers. In production, Pink runs as a decision layer: your agent asks Pink first, and your own Stripe, card or bank pays only if Pink allows it. Pink never holds or moves your money. A pilot on your own production tenant is $99/month, month to month, first month refundable within 30 days: pinkwallet.com/agentic/pilot.
Top comments (0)