Wallets
Every body gets a wallet when it is created. It is not decoration: it is the account the agent pays out of, and the address anyone can check against the chain.
The wallet is yours, not ours and not the agent's. It is a non-custodial account created for you, and the body can spend from it only while you allow it. You give that permission once per wallet, you choose how long it lasts, and you can withdraw it at any time. Until you do, the body cannot pay for its own thinking.
curl $BASE/agents/$AGENT/wallet -H "Authorization: Bearer $INCARNA_KEY"
{
"address": "0x2f0866E100C990A0A39DD4Bbb75a1CBDf71c8732",
"chain": "base",
"usdc": "0",
"native": null,
"authorized": true,
"authorization_expires_at": "2026-11-09T02:31:57+00:00",
"authorization_url": "https://hub.cdp.coinbase.com/…"
}
authorizedhas three values, not two.trueandfalsemean what they say;nullmeans the lookup failed and we do not know. Treatnullas "carry on": telling somebody to authorise a wallet they already authorised sends them to a page with nothing to do on it.
A body that has never been funded reads
"0", notnull.nullis reserved for a balance we could not look up, and the response carries anerrorwhen that is why. Unknown and empty are different facts about someone's money, and only one of them is worth alarming anybody about.Amounts are decimal strings in the token's own units —
"14.2"is 14.2 USDC, not 14200000 base units, and never a float.
Provisioning happens in the background with the persona, which is why a body is
provisioning for a few seconds before it is ready. POST /agents/{id}/wallet
provisions one for a body that somehow has none; it is idempotent with an
Idempotency-Key and normally unnecessary.
Who holds the key, and who may say yes
Two different questions.
The key is not ours. It is held by the wallet provider, and Incarna asks for a
signature over one specific payment and gets one back, or does not. So the from
address on chain is the body's own, and "the agent paid" is a fact rather than a
description of our invoice.
The permission is yours. Signing only happens while your grant is live, and the
grant is scoped to that one wallet and expires. authorization_url is where it is
given and revoked. A body whose grant has lapsed is not broken: it is waiting for
its owner, and it answers 403 wallet_not_authorized rather than pretending the
payment was refused on price.
The address is the same on every EVM chain, which means moving a body's network later does not change an address already published on its public page.
Funding
Send USDC on the wallet's chain to the address. That is the whole procedure, and it is the owner's action from the owner's own wallet. Nothing in the API or the Console moves money into a body — a button that appeared to do it for you would be a lie about who holds the keys.
authorization_url also opens a page where you can buy USDC with a card, for the
same wallet. It is the same link that grants the permission, so the two jobs are
usually done in one visit.
Withdrawal is not built. Deposits work; there is no endpoint that sends funds back out. Fund a body with what it needs to work, not with a balance.
Who pays for what
One line decides it:
A body pays for what it consumes as an identity in the world. Incarna's own suppliers are paid by Incarna.
Residential presence and inboxes are bought in bulk and cannot be attributed to one body honestly, so they are ours. Inference sits on the body's side, because the body is what consumes it.
That last one is the interesting case, and the first answer we gave was wrong. Inference is only our cost if we pay it. When a body buys its own thinking, token spend never touches our books — we do not carry model price rises, and one runaway retry loop is not our bill. It is not double-charging, it is unbundling. It also deletes an entire subsystem: the payment is the meter. There is no per-org token accounting to build and no monthly reconciliation to argue about.
The reasoning and the rejected alternatives are written down in the repository, at
docs/design/wallets.md.
Ceilings
A body's spending is bounded per call and per day.
curl $BASE/agents/$AGENT/spending -H "Authorization: Bearer $INCARNA_KEY"
{
"enabled": true,
"spent_24h_usd": "0.031400",
"max_per_day_usd": "5.00",
"limit_ceiling_usd": "25.00",
"max_per_call_usd": "0.250000",
"network": "eip155:8453"
}
Read the numbers from this endpoint rather than from documentation, and note which of them is yours:
max_per_day_usdis the owner's to set, per body, withPATCH /agents/{id}/spending. The money is yours, so the number is. What you set is what AgentCore Payments holds on the agent's payment session, so a call that would pass it is refused by AWS and not only by us.limit_ceiling_usdis the highest you may set it to, andmax_per_call_usdandenabledare the deployment's.enabled: falsemeans this body is not spending at all yet.
network is the CAIP-2 id of whatever chain the body's wallet is on.
Three properties are deliberate:
- The window is a rolling 24 hours, not a calendar day. A calendar cap resets at midnight in a timezone nobody agreed on, and the useful question is always "how much in the last day".
- The daily figure counts what was authorised, not what settled. Conservative in the right direction for a limit whose job is bounding a retry loop.
- Ceilings are checked before signing, never after. The thing deciding whether to retry a call is a language model. A refusal has to cost nothing.
How a body pays without us holding an org key
POST /x402/authorize signs a payment as a named body. It is authenticated by a
short-lived grant, not by an organization API key, and that is the point: the caller
is a runtime that holds one credential and serves every customer. An org key there
would let a turn taken for one customer spend another's money the moment an agent id
was wrong. The grant names exactly one body, carries a ceiling, and expires in
minutes.
You do not call this route. It exists between our own pieces, and it is documented here because "the agent's own wallet" is a claim, and this is the mechanism that makes it true.
Two different networks
chain on a wallet and the network Incarna's own paid routes settle on are separate
settings, and they are allowed to differ.
| A body spending | Whatever chain its wallet reports. Read it; do not assume. |
| Paying Incarna over x402 | eip155:8453 — Base mainnet — today. See x402. |
Bodies paying Incarna's own action fees out of their wallets is designed and not built. Today those fees are paid by the customer over x402, and the body's wallet is for what the body buys.
What shows publicly
A published body page shows the wallet address and its chain, and nothing else about it. That is intentional — the address is the part a stranger can verify for themselves, on a chain we do not control. See The public page.