How to Give an AI Agent Its Own Wallet and Spending Limits with Pink

To give an AI agent its own wallet and spending limits, create an agent inside Pink Agentic AI Payments: each agent gets its own key, its own vault balance, a monthly budget, a per-payment cap, and a set of rules that decide every payment before a credential is ever issued. The agent asks; Pink's server, not the agent, decides whether a payment is allowed, needs a human, or is blocked.

The three objects that make up an agent's "wallet"

Pink doesn't use the word "wallet" for a single object; an agent's spending identity is three linked pieces, each with its own real fields (confirmed against the live sandbox and its OpenAPI spec):

Object What it holds Key fields
Agent The identity an MCP/REST call authenticates as id, name, department, status (active/paused), its own vault
Budget The money limits attached to that agent monthly_budget, spent_this_month, left_this_month, single_payment_cap, company_daily_ceiling, company_spent_today
Vault The actual funding source the agent draws from id, name, purpose, balances (a currency-to-amount map)

GET /v1/budget, called with that agent's key, returns all of this in one response, including the vault's current balance. A vault can be shared by more than one agent's rules, but each agent's own budget and cap are tracked separately from it.

Step 1: create the agent and its vault

In the sandbox, POST /v1/sandbox/workspaces seeds a workspace with a company, a set of agents, payees, and a starter rule set from a template (coffee, startup, or ecommerce). In production, the console is where an admin creates an agent, assigns it a vault, and issues its key; the agent key is the only credential that agent-side code ever holds; it cannot read another agent's vault or the admin key.

Step 2: set the budget and the per-payment cap

Two numbers, set once per agent:

  • monthly_budget and the running spent_this_month it's checked against.
  • single_payment_cap, the most that agent can move in one payment before a rule (not just the raw cap) has to approve it.

A third number applies to every agent together: company_daily_ceiling, checked against company_spent_today regardless of which agent is spending. All three are circuit breakers, checked before any named rule, in this order: is the agent registered and active, is the monthly budget under its limit, is the company under its daily ceiling, does the vault hold the balance.

Step 3: write the rules

A rule is a JSON object with a fixed schema (from Pink's policy rules reference):

{
  "id": "r18",
  "name": "Supplier reorders under $2,000: automatic",
  "agents": ["a_proc"],
  "payee": "approved",
  "min": 0,
  "max": 2000,
  "window": "tx",
  "action": "allow"
}
Field Values Meaning
agents "*" or a list of agent ids Which agents this rule covers
payee any · approved · new · cat:<category> · a list of payee ids approved = on this agent's payee list, new = not on it, cat:ads/cat:saas/cat:blocked/etc. match by category
min / max numbers, USD-equivalent the inclusive range the measured amount must fall in; max: null means unbounded
window tx · day · month whether the amount is measured per transaction, per day, or per month for that agent
action allow · ask · block what happens on a match; ask requires approvers
approvers {"people": [ids], "n": 1} or {"group": id, "n": 2} named people or a quorum of a group
requires / absent a flag name the rule only matches if the request carries, or doesn't carry, that flag
outsideHours [start, end] in 24h, workspace-local restricts the rule to outside that time window

Rules are evaluated top to bottom; the first match wins; nothing matching any rule is blocked by default, not allowed.

Step 4: what happens when a request exceeds a rule

Calling pink.request_payment (or POST /v1/payments) returns one of three outcomes. On a live sandbox workspace, a $900 request against a $500 auto-allow tier matched an ask rule and returned:

{
  "decision": "pending_human",
  "hold_id": "pay_935e89f7f4c4",
  "approvers_needed": 1,
  "who": "Luis Ortega (Store manager)",
  "expires_at": "2026-10-12T12:23:27.891Z"
}

A $420 request under the same agent's per-payment cap returned HTTP 201 with a single-use bank-transfer credential in the same call, locked to that payee and amount, expiring 15 minutes after issue. No credential is ever issued for a blocked or still-pending_human request.

Worked example: a procurement agent's config

Setting Value
Agent a_proc, department "Procurement"
Vault Operating, balance checked live on every request
monthly_budget $4,000
single_payment_cap $500 (auto-allow tier)
company_daily_ceiling $6,000, shared across all agents
Rule r18 approved payees, $0–$2,000, tx window, allow
Rule r19 approved payees, $2,000–$10,000, tx window, ask, approver group g_supply
Rule r11-style block cat:blocked payees (gift cards, crypto, cash-like) always block

How the limits hold up under real concurrent load

A live test run against the sandbox fired 40 concurrent $200 payment requests from a single agent against a $6,000 company daily ceiling: exactly 30 were allowed (summing to exactly $6,000) and 10 were blocked, with the server's own ledger matching that split. A second run tested one agent's monthly budget under the same kind of concurrent load: 8 requests were allowed before the budget ran out, and further requests were blocked.

A separate sandbox test checked whether the shared ceiling still holds when multiple agents hit it at once, not just one. Three agents (a purchasing agent, an inventory agent, and a payroll agent) fired 40 payment requests concurrently against the same $6,000 company daily ceiling, in two runs. In run 1, 27 of 40 were allowed, totaling $5,720 (plus $180 already spent that day, for $5,900 against the $6,000 ceiling); in run 2, 32 of 40 were allowed, totaling exactly $6,000. Every one of the 21 blocked requests across both runs returned the reason "Company daily ceiling reached" with the running total (for example, "$5,900 + $110 > $6,000"), and the client-side allowed totals matched the server's own company_spent_today ledger exactly in both runs. This is observed sandbox behavior from a single test session, not a claim that the underlying check is "atomic" or lock-based, and it has not been run against production.

Current limits

Everything above runs against Pink's public sandbox at agentic-sandbox.pinkwallet.com: free, no signup, test money only. Production use, with a real vault and real payment rails, is early access via the waitlist at pinkwallet.com/agentic/developers/ and is not yet generally available.

FAQ

Can every AI agent have its own separate spending limit instead of sharing one company card? Yes. In Pink, each agent gets its own monthly_budget and single_payment_cap, checked independently of other agents, plus a shared company_daily_ceiling that applies across all agents together.

What exactly is an agent's "wallet" in Pink's terms? There's no single "wallet" object; it's three linked pieces: the agent (identity and key), its budget (the limits), and a vault (the actual funding source and balance). GET /v1/budget returns all three together.

Can I set a limit per payment and a limit per month at the same time? Yes, these are separate fields: single_payment_cap for the per-transaction limit and monthly_budget for the running monthly total, and a rule's own window field (tx, day, or month) can add a third, finer-grained limit on top.

What happens if an agent tries to spend past its limit? The request is blocked before any rule is even evaluated; circuit breakers for budget, daily ceiling, and vault balance run first. No credential is issued.

Does the limit hold up if the agent fires many requests at once? In a tested run, 40 concurrent $200 requests against a $6,000 daily ceiling resulted in exactly 30 allowed ($6,000 total) and 10 blocked for a single agent, matching the server ledger. In a separate test with three different agents firing 40 concurrent requests together against the same shared $6,000 ceiling, the total allowed across all agents still landed at exactly the ceiling (or just under it) in both runs, with every block citing the ceiling by name.

Is this limited to one currency? Rules can be scoped to a specific currency (USD, EUR, GBP, HKD, SGD, or JPY) via the rule's currency field, or left currency-agnostic.

Related reading