# agents.u.cash > The agent + merchant product surface for the 402 Online Protocol — multi-coin, non-custodial HTTP-402 payments for AI agents, humans, and merchants. Two-sided: the same account can SELL (get paid to its own wallet) and BUY (pay for resources). A live reference implementation. Protocol spec: https://402.onl ## Key properties - Non-custodial: every payment goes direct buyer->seller (the seller's own wallet). The platform never holds funds or keys; it only verifies, detects on-chain, and notifies. Not a money transmitter. - Multi-coin: detect scheme covers BTC (+Lightning), ETH + all ERC-20s, USDT, USDC, Solana, Tron, XRP, Monero, UCASH, and custom tokens — anything with an address. - Two-sided: an agent can both sell (create priced resources) and buy (pay for others' resources). - Agent-native: API-key auth, idempotent verify, HMAC-signed webhooks, a settlement ledger, and an MCP tool surface (see 'For AI agents'). - Buyer-push verify: a buyer needs no seller key — the public challengeId authorizes a verify, gated by on-chain confirmation. ## Auth Send the api_key from POST /v1/signup in the X-Api-Key header. Accounts are activated by a confirmed >= $1 top-up (POST /v1/top-up). Until activated, authenticated endpoints return 402 uxc_agent_not_activated (top-up itself is allowed pre-activation). ## Concepts - resource (res_id): a priced listing a seller creates (fiat amount + accepted assets). NOT a single transaction — it accepts many coins. - accepts[]: the multi-coin 402 challenge — one entry per accepted asset {scheme:'detect', asset, network, payTo (the seller's own address), amount (exact, randomized), challengeId, expiresAt}. - challengeId (chal_...): links a buyer's payment to a specific resource+asset; used to verify. Public (safe to share); settlement still requires real on-chain payment. - settlement: a completed resource payment (status C). Recorded read-only in the seller's settlement log; funds already went to the seller's wallet. ## Account endpoints (all require X-Api-Key except signup) - POST /v1/signup {email, password, primary_wallet?} -> {api_key, activated:false, next} [no key; wallet-first, no email loop] - POST /v1/top-up {amount} -> {url, amount, activated, next} [>= $1; the URL pays+activates; allowed pre-activation] - GET /v1/agent -> {email, activated, primary_wallet, credit_balance, webhook_url, stripe_configured, custom_tokens[{code,type,network,name,contract_address,decimals,confirmations?}], wallets{asset:address}, settlements_count, total_earned} - Human operators can also sign in to the full dashboard at https://pay.u.cash/admin with the email + password from signup to view the agent 402 sales, credit balance, and per-sale fee history. - POST /v1/agent {webhook_url} -> sets the settlement webhook URL - POST /v1/wallets {asset, address} -> {asset, address} [sets your own receive address for an asset — where buyer funds land] - POST /v1/stripe {secret_key, product_id, webhook_secret, publishable_key?} -> masked config + webhook_endpoint [connect your OWN Stripe account to enable card payments (the redirect rail); key + product are verified against Stripe first; secrets are never returned in full; non-custodial — card payments settle direct to your Stripe] - GET /v1/stripe -> masked Stripe config + the webhook endpoint URL to register (subscribe checkout.session.completed) - DELETE /v1/stripe (or POST {clear:1}) -> disconnect Stripe (disables the card rail) - POST /v1/custom-tokens {type, code, contract_address, decimals, name, rate?, rate_url?, confirmations?} -> the stored token [self-serve a custom token: type is erc-20/bep-20/base-20/polygon-20/arb-20/op-20/avax-20/trc-20/spl (picks the chain); code must not collide with a built-in coin; contract + decimals; then POST /v1/wallets {asset:code, address} to set where buyers pay — the token is auto-detected on-chain like any coin] - GET /v1/custom-tokens -> {custom_tokens:[{code, type, network, name, contract_address, decimals, confirmations?}]} - DELETE /v1/custom-tokens?code= -> removes one custom token - GET /v1/settlements -> {settlements:[{transaction_id, res_id, asset, amount, amount_fiat, currency, status, tx_hash, created_at, settled_at}]} ## 402 payment endpoints - POST /v1/resources {amount, currency?=USD, accepted_assets?=all wallets, webhook_url?} -> {res_id, amount, currency, accepted_assets} - POST /v1/challenge {res_id} -> {res_id, amount, currency, accepts:[...]} [mints/reuses per-asset challenges; idempotent within TTL] - POST /v1/verify {challengeId, hash} -> {settled:true, transaction_id} | {settled:false, status:'pending', confirmations, required} | {status:'underpaid'} [optional instant settle — the platform also auto-detects the on-chain payment; buyer-push, no key needed; or seller key] - GET /r/{res_id} -> HTTP 402 + {accepts[]} (machine) OR a payable HTML page (browser, Accept: text/html) OR 200 {settled:true} if paid. Public, no key. ## Sell flow (become a seller) 1. POST /v1/signup -> api_key. 2. POST /v1/top-up {amount:1}, pay the URL -> activated. 3. POST /v1/wallets {asset:BTC, address:bc1q...} for each coin you accept. 4. POST /v1/resources {amount:0.05} -> res_id. 5. Share https://agents.u.cash/r/{res_id}. 6. On payment, you get an HMAC-signed webhook + the settlement appears in GET /v1/settlements. Buyer funds went straight to your wallet. ## Card rail (optional) To also accept card payments, POST /v1/stripe {secret_key, product_id, webhook_secret} with your OWN Stripe account keys (the key + product are verified against Stripe before storing). Then register the returned webhook_endpoint (subscribe checkout.session.completed) in your Stripe dashboard. Buyers then see a redirect (card) entry in accepts[] alongside the coin entries; card payments settle direct to your Stripe account (non-custodial). The platform fee is debited from your prefunded credit. GET /v1/stripe returns the masked config + the endpoint to register; DELETE /v1/stripe disconnects. ## Custom tokens (optional) To accept a token that is not built in (an ERC-20/BEP-20/Base/Polygon/Arbitrum/Optimism/Avalanche/TRC-20/SPL), POST /v1/custom-tokens {type, code, contract_address, decimals, name} to add it to your account, then POST /v1/wallets {asset:code, address} to set where buyers pay it. The token is auto-detected on-chain like any built-in coin (the cron scans the contract transfers). GET /v1/custom-tokens lists them; DELETE /v1/custom-tokens?code= removes one. ## Settings GET /v1/settings -> {confirmations:{default, coins:{:n}, increase:{threshold, percentage}}, webhook:{url, secret}, currency, payment:{accept_underpayments, redirect}, notifications:{email}, branding:{brand_name, logo_url, logo_url_dark, color_1, color_2, color_3}}. PUT /v1/settings {any subset} updates (partial). webhook.secret is returned so you can verify the HMAC (X-Webhook-Signature) on settlement webhooks — send webhook.rotate_secret=true to mint a new one. This is the safe subset only; nothing custodial/node/private-key/payout/multi-store is exposed. notifications.email defaults to your signup email when unset, so sale + underpayment notices work out of the box. ## Fees The buyer pays the seller the full amount, direct — to the seller's own wallet (detect) or the seller's own Stripe account (redirect). The platform never touches the payment. The platform fee is a small percentage that the seller prepays as a non-withdrawable credit balance; it is debited separately when a sale settles — never taken from the payment, never held. No intermediary ever controls the transaction funds. ## Private by design No custodial accounts, no KYC, no held balances. The platform sees only resource metadata and on-chain payment confirmation — it holds no user funds and no user private keys. Every payment is peer-to-peer, direct buyer->seller. That is what keeps it out of money-transmitter scope. ## Human oversight Agents transact autonomously, and the human behind each agent has full oversight: sign in to the dashboard at https://pay.u.cash/admin with the signup email + password to audit, track, and analyze every transaction — the 402 sales, settlements, credit balance, and per-sale fee history. Autonomy and transparency, together. ## Buy flow (pay for a resource) 1. GET /r/{res_id} -> accepts[] (or the HTML page in a browser). 2. Pick an entry; pay entry.payTo exactly entry.amount from your wallet (out of band — the API never touches your keys). 3. The platform detects the on-chain payment and settles automatically (within a few minutes). Optionally POST /v1/verify {challengeId, hash} to settle instantly (poll while confirmations accumulate). No seller key needed; no client proof required. ## Webhooks On settlement, agents.u.cash POSTs an HMAC-signed (X-Webhook-Signature: t=..,v1=..) JSON {transaction, event_id} to your configured webhook_url. Verify the signature with your webhook secret; the body is authoritative (never trust amounts from the request). ## Rate limits (per-IP fixed windows; over -> 429 uxc_rate_limited) signup 10/hr, top-up/resources/challenge/verify/settlements/agent 30-60/min, /r/ 120/min. ## For AI agents - MCP server (drive the seller surface as tools, e.g. in Claude Desktop): https://github.com/UdotCash/agents-u-cash/tree/main/agents/mcp — env UXC_API_KEY, tools: uxc_get_agent, uxc_set_wallet, uxc_create_resource, uxc_list_resources, uxc_create_challenge, uxc_get_settlements, uxc_view_door, uxc_verify_payment. - SDKs (zero-dependency): JS `npm install agents-u-cash`, Python `pip install agents-u-cash` — https://github.com/UdotCash/agents-u-cash/tree/main/sdk - Structured API: this server's OpenAPI at https://agents.u.cash/openapi.json ## Agentic discovery + checkout (UCP) Each merchant business is machine-discoverable + buyable via UCP (ucp.dev, an open standard, not Stripe). Discovery: GET /catalog.json (or a merchant custom domain, or pay.u.cash?cloud=) returns a schema.org/Product JSON-LD catalog; GET /catalog.txt is a plain-text index; GET /.well-known/ucp returns the UCP profile (catalog.lookup + checkout + ap2_mandate capabilities, our non-custodial detect + redirect payment handlers, an EC signing key). Checkout sessions are the UCP buyer flow (resolve the merchant from the host or ?cloud=; no X-Api-Key): - POST /checkout-sessions?cloud= {line_items:[{item:{id}, quantity}], currency?, buyer?, context?} -> {id, status, currency, line_items, totals, ap2:{merchant_authorization, nonce}}. Multi-item + mixed-currency carts: per-item keeps its original amount+currency; the cart total converts to the cart currency (the `currency` field, else the merchant default). - GET /checkout-sessions/{id}?cloud= -> the session (status: incomplete -> ready_for_complete -> completed). - POST /checkout-sessions/{id}/complete?cloud= {ap2?:{checkout_mandate}} -> ready_for_complete + payment_handlers[] (the per-coin detect challenges + the redirect). AP2 is optional (dev.ucp.shopping.ap2_mandate): submit a buyer-signed checkout_mandate (SD-JWT-VC) for holder-proof authorization; it is verified (issuer signature + checkout-hash binding + key-binding JWT + open-mandate constraints), else 401 mandate_invalid_signature / mandate_expired / mandate_scope_mismatch. - POST /checkout-sessions/{id}/cancel?cloud= -> canceled. - GET /orders/{id}?cloud= -> the order (per-item fulfillment status; completed once every line item settles). - POST /catalog/search | /catalog/lookup | /catalog/product ?cloud= -> structured catalog access (search with filters, batch lookup by id, single product). Every merchant-origin response is RFC 9421-signed (ES256) with the profile key (Content-Digest + Signature-Input + Signature headers); signed inbound requests are passively verified. Settlement is async + non-custodial: the buyer pays each item's challenge on-chain (detect) or via the seller's Stripe (redirect); the session reaches completed once all items settle. SDK helpers: agents-u-cash createCheckout / getCheckout / completeCheckout / getOrder. ## Error envelope Errors: {success:false, error_code:'uxc_*', message}. Common: uxc_unauthorized (401), uxc_agent_not_activated (402), uxc_rate_limited (429), uxc_not_found (404), uxc_invalid_request (400), uxc_challenge_expired, uxc_replay (reused tx hash). ## Links - Protocol spec (vendor-neutral): https://402.onl - This API's OpenAPI: https://agents.u.cash/openapi.json - Source / SDKs / MCP: https://github.com/UdotCash/agents-u-cash