Build an agent that pays on its own, within a cap it cannot raise
Most agents can plan a purchase and then stop at the invoice. The gap is not reasoning, it is money: no wallet, and on the day someone hands the agent a key, that key sits in an env file with no ceiling attached to it.
Most agents can plan a purchase and then stop at the invoice. The gap is not reasoning, it is money: no wallet, and on the day someone hands the agent a key, that key sits in an env file with no ceiling attached to it.
This walkthrough closes that gap for a Claude agent. It gets a hosted wallet, a daily spending limit that is checked on the server before anything is signed, and a pay_for_service tool it can call without a human in the loop. The agent never sees a private key, and nothing in its prompt can raise its own cap.
What the cap is, exactly
A policy in OpenClawCash is a rule attached to a wallet, not a line in your system prompt. Spending limit policies come in daily, weekly and monthly windows, and every request is checked against them before signing. If the policy says no, the request never reaches the chain, so a jailbroken prompt, a runaway loop or a leaked agent key all hit the same wall.
You can read the policy and its live usage over the API at any time, which is the part most agent wallets leave out.
Step 1: create the wallet
Sign up at openclawcash.com, then create a wallet in the dashboard and give it a label you will recognise in logs, for example agent-wallet-01. Choose the network at creation time, Ethereum, Polygon or Solana. You can import an existing private key instead; it is encrypted server side and the agent API never exposes it.
Then ask the API which wallet you are talking to. walletId is what every later call wants:
curl https://openclawcash.com/api/agent/wallets \
-H "X-Agent-Key: occ_your_api_key"
# returns, per wallet:
# { "id": "Q7X2K9P", "label": "Trading Bot", "address": "0x14ae8d93...",
# "network": "sepolia", "chain": "evm" }
Step 2: set the spending policy
In the wallet's policy controls, set the limit you are willing to lose in a day, and add the addresses the agent is allowed to pay. Anything not on the list is rejected before the transaction is built.
Be honest about the trade-off: policy changes go through the dashboard for now, not the API. Payments run fully autonomous while a human still has to be present to widen the cap.
Step 3: mint an agent key
Create a key scoped to that wallet under API Keys, and keep it out of your source tree:
export OCC_AGENT_KEY=occ_your_api_key
One agent, one key, one wallet. A leaked key costs you that key, not the fleet.
Step 4: read the remaining budget
Before the agent pays anything, it should be able to answer "how much is left today". This is a plain GET:
curl "https://openclawcash.com/api/agent/policy?walletId=Q7X2K9P" \
-H "X-Agent-Key: occ_your_api_key"
{
"wallet": { "id": "Q7X2K9P", "label": "Trading Bot" },
"policies": [
{
"id": 31,
"type": "daily_spending_limit",
"config": { "amount": "100" },
"usage": { "spent": "45.00", "limit": "100.00", "symbol": "USD", "window": "24h" }
}
]
}
Feed usage back to the model as part of its context. An agent that can see 55 USD of headroom makes better decisions than one guessing.
Step 5: let it pay
The transfer endpoint takes a wallet selector, a recipient, a token and an amount in human units. Exactly one amount field per call:
curl -X POST https://openclawcash.com/api/agent/transfer \
-H "Content-Type: application/json" \
-H "X-Agent-Key: occ_your_api_key" \
-d '{
"chain": "evm",
"walletId": "Q7X2K9P",
"to": "0xRecipientWalletAddress...",
"token": "USDC",
"amountDisplay": "1.50"
}'
amountDisplay is the decimal form, valueBaseUnits is the integer form, and sending both is a 400. Older code that sends "amount" still works, it is a deprecated alias.
The response gives you txHash, status, the adjusted amount and the fee breakdown, which is what you want to log next to the agent's own reasoning.
Step 6: the tool that calls it
The agent decides when to pay. Your code decides whether it can. This is the whole tool definition:
import os, requests
AGENT_KEY = os.environ["OCC_AGENT_KEY"]
WALLET_ID = "Q7X2K9P"
PAYEE = "0xServiceProviderAddress..."
def remaining_budget() -> dict:
r = requests.get(
"https://openclawcash.com/api/agent/policy",
headers={"X-Agent-Key": AGENT_KEY},
params={"walletId": WALLET_ID},
)
return r.json()
def pay_for_service(amount: str) -> dict:
r = requests.post(
"https://openclawcash.com/api/agent/transfer",
headers={"X-Agent-Key": AGENT_KEY},
json={
"chain": "evm",
"walletId": WALLET_ID,
"to": PAYEE,
"token": "USDC",
"amountDisplay": amount,
},
)
return r.json()
Register both as tools and put the policy response in the system context. The model still chooses the amount. The server still refuses anything over the cap, or to any address you did not list. A paying agent whose only limit is a sentence in its prompt is not a guardrail, it is a wish.
Where this gets rough
Two things will bite you, both documented. Native transfers run a preflight for the minimum transferable amount, so a dust payment to a fresh Solana address fails with amount_below_min_transfer and retryable: false; fund the recipient properly or send a token instead. And a Solana memo is capped at five words, so do not stuff an invoice id and a description into it.
The two commands that matter
Read the budget, then pay: GET /api/agent/policy?walletId=... and POST /api/agent/transfer. Everything else in this setup is a dashboard click, and the cap you set there is the reason you can leave the agent running.
The full API surface, including escrow, swaps and webhooks, is at openclawcash.com/docs.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.