The hosted-action flow: what the user sees when the agent pays, and why the user is in the loop on every transfer
When the agent you build wants to pay, you are in the loop. This is the part of CAI the user sees most often, and the part most agents get wrong. This post walks through the hosted-action flow in detail: the wallet_custodial_transfer call, the confirmation page, the user tap, and the receipt poll.
The call
The agent calls POST /wallet-custodial-transfer with the recipient, the amount, the chain, and the token. The CAI Edge API processes the request and returns a hosted-action URL.
curl -X POST https://api.cai.com/functions/v1/wallet-custodial-transfer \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{
"to_address": "0x...",
"amount": "10.00",
"chain": "base",
"token": "USDC"
}'
The response:
{
"transfer_id": "tx_...",
"hosted_action_url": "https://cai.com/act/...",
"expires_at": "2026-07-04T12:34:56Z"
}
The hosted_action_url is a single-tap confirmation page. The user opens it, sees the recipient, the amount, and the chain, taps once, and the payment goes through.
The confirmation page
The hosted-action page is a CAI-hosted HTTPS page. The page shows:
-
The recipient, the
to_address(and a resolved name if one is available). - The amount, the exact amount in the chosen token.
- The chain, the chain the payment will go on.
- A single button: "Confirm" or "Cancel."
The user taps "Confirm" and the payment goes through. The user taps "Cancel" and the payment does not go through. The user does nothing and the payment does not go through (the URL expires in a short window).
The page is bound to a single transaction. The URL cannot be reused for a different recipient, amount, or chain. The URL is single-use; once the user taps, the URL is invalidated.
Why the user is in the loop
The hosted-action flow is the user-confirmation pattern. Three roles:
- CAI is the custodian. CAI holds the private key. The user does not.
- The user is the approver. Every transfer needs the user's tap on the hosted-action page.
- The agent is the operator. The agent calls the API, returns the URL, polls for the receipt.
The agent's API key is the authorization: it can call the CAI API on the user's behalf. The user's tap on the hosted-action page is the consent: it can authorize a specific transfer.
This is the difference from a model where the agent has the user's private key and signs transactions autonomously. With CAI, the agent never has the private key. The agent has the API key (which gates access to the CAI API) and the hosted-action URL (which gates the actual transfer).
The receipt
After the user taps "Confirm," the agent polls POST /transfer-status for the receipt.
curl -X POST https://api.cai.com/functions/v1/transfer-status \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{
"tx_hash": "0xabc123..."
}'
The response includes the on-chain tx hash when the transfer is confirmed. The agent can then show the receipt to the user.
Polling cadence: the agent should poll every 2-5 seconds. The transfer typically confirms within 10-30 seconds on Base, 30-60 seconds on Ethereum mainnet. Longer polls are fine for non-urgent transfers; the URL itself expires in a short window, so the agent should not wait too long.
Failure modes
The hosted-action flow has three failure modes the agent should handle:
- URL expired before user tapped. The transfer is cancelled. The agent should report the timeout to the user and re-initiate if the user wants to retry.
- User tapped "Cancel." The transfer is cancelled. The agent should respect the cancellation and not retry without explicit user direction.
-
Transfer failed on-chain. The agent receives a
failedstatus fromtransfer_status. Common causes: insufficient balance, gas estimation failed, recipient address invalid. The agent should report the specific error to the user.
In all three cases, the agent's API key is unchanged. The hosted-action flow is per-transfer; a failed or cancelled transfer does not affect subsequent transfers.
Why this design
The hosted-action flow is the practical implementation of "the user is in the loop on every privileged action." The same pattern applies to the vault (the POST /user-site-credentials call returns a hosted-action URL for the user to confirm). The pattern is consistent across every state-changing operation in CAI.
The alternative designs are worse:
- Agent has the private key. The agent signs transactions autonomously. The user has no visibility. A compromised agent drains the wallet.
- Agent has the user's password. Same problem for the vault. A compromised agent logs in to every site the user has saved.
- User pastes a private key into the agent conversation. The private key ends up in the model's context window. The model may log it. The user has to rotate the key.
CAI does none of these. The user-confirmation pattern is the only safe way to give an agent access to a wallet or a vault.
Spending and safety limits
Every CAI wallet starts with a $200/day automatic spending limit on transfers. This cap applies regardless of the wallet balance. If a transfer would exceed the daily limit, the agent must wait or the user can adjust the cap in the dashboard.
First-time transfers to a new recipient address trigger an additional confirmation step. The user sees the full address and has to confirm it is correct before the transfer proceeds. This prevents a compromised agent from sending funds to an attacker without the user noticing.
The hosted-action flow is documented in cai.com/agent-payment.html (the H1-readable cut) and cai.com/skill.md (the API surface). Apply at cai.com/app to get a wallet.
If you triggered a hosted-action and the confirmation page didn't render, or the transfer_status poll never resolved
Comment below with:
- What you ran, the install command, the request, the MCP host config. Copy the actual command or request.
- What you expected, one sentence.
- What you got, the error message, the empty response, the unexpected behavior. Paste it verbatim.
- Your environment, OS, Node version, the MCP host (OpenClaw / Hermes / Codex / Cursor / other), the CAI account tier if relevant.
Every comment on this article gets read. Bug reports will be replied to within 24 hours. Friction points shape what we document next.
Documentation: cai.com/skill.md · cai.com/developers.html · cai.com/app to sign up.
Top comments (0)