# PayHumans.ai: agent guide > PayHumans lets an AI agent get a real-world fiat payment made. The agent funds an order with supported crypto and names a recipient; a person sends the money from their own payment app and collects the crypto once the payment is verified. Built on Peer. Reviewed 2026-10-04. Source of truth for flags: `payhumans --help` in the version you installed. HTML version: https://payhumans.ai/docs ## Rules to hold before you spend anything 1. Creating an order does not pay the recipient. It puts crypto in escrow and waits for a person. Only a claim in the FULFILLED state means a fiat payment was verified and USDC was released. 2. Every command that spends is a preview until you pass `--yes`. Preview first and read `totalSourceInput`, `routes` and `fiatForFullDeposit` (amount times rate: the fiat the recipient gets if the whole order fills). 3. Signed crypto writes require `--operation-id`. `deposit create --yes` also requires `--max-source-spend`; `return --yes` requires `--min-receive`. Recipient registration moves no crypto and needs no operation ID. Reuse the same operation ID on every retry; a new ID is a new payment. 4. Retry protection depends on the local journal in `~/.payhumans/operations`. Keep that directory and back it up, and do not use the same wallet from another process or tool while an operation is in flight. Without the journal the CLI cannot tell what was already sent. 5. The limits bound the route and execution gas, not every cost. L1 data fees, Solana account rent and your own Bitcoin transaction fee are extra. Each limit covers one order, so keep your own total budget. Gas caps are checked against prepared transactions during execution; a preview is not a full gas estimate, and earlier confirmed steps can remain spent if a later step is blocked. 6. Keys come only from the environment: `PAYHUMANS_SOLANA_KEY` or `PAYHUMANS_EVM_KEY`, or their `_FILE` variants. Never put a key in a command argument, a prompt or a log. No account, API key or Privy login is needed. 7. Whatever you fund with is converted to USDC on Base before the deposit. The escrow is Peer's contract on Base. There is no escrow on Solana, Ethereum or Bitcoin. 8. Funded mainnet tests cover Solana USDC/SOL, Ethereum ETH, Base ETH and external-wallet native BTC. Other implemented routes remain untested with funds. A successful quote alone is not a funded test. Wrapped BTC is not accepted. 9. Recipient validation checks format, not ownership. Confirm the exact handle with the recipient. Fiat sent to a wrong handle cannot be recovered. 10. Nobody is guaranteed to see or fill an order. 12 platforms can be named in an order, but only 10 can be filled in the Peer mobile app. Unclaimed funds can be withdrawn at any time. You cannot cancel another person's active claim, and should not try to: they may already have sent fiat. 11. Real fiat payment, proof and payout remain unverified in these PayHumans tests. Start with small amounts. ## Overview PayHumans turns a payment an agent wants made into an order a person can fill. The agent locks crypto in escrow and states the terms: who gets paid, on which payment platform, in which currency, and at what rate. A person claims the order, sends the fiat from their own account, proves the payment, and receives the crypto. Two things move, in two places. Crypto moves on-chain between the agent, the escrow contract and the person who pays. Fiat moves off-chain, from that person's payment account to the recipient. A proof of the fiat payment is the only thing that connects them. Sequence: 1. Agent funds an order. Its crypto is converted to USDC on Base and locked in Peer's escrow with the recipient, platform, currency and rate. 2. A person claims some or all of it in the Peer app. That amount is reserved for them for a limited time. 3. They send the fiat to the recipient from their own payment account. 4. They prove the payment. Peer checks it against the claim: recipient, amount, currency and timing. 5. The escrow releases the reserved USDC to that person, less Peer's fees. With no valid proof in time, the claim expires and its funds return to the order once the expired claim is cleared. ## Where funds sit - The escrow is Peer's production escrow contract on Base (chain ID 8453). PayHumans deploys no contracts of its own. - The escrow holds USDC on Base: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`. - Funding from another chain or asset means a swap or bridge into USDC on Base, carried out by a routing provider before the deposit. There is no escrow on Solana, Ethereum or Bitcoin. - The order belongs to your Base account. With an EVM key, that is the key's own address. With a Solana key, the CLI derives a Base account from the key, so you still manage one secret. Keep that key: it is the only way to withdraw. - PayHumans never holds funds or keys. The CLI signs locally. Between the route and the deposit, funds sit in your own Base account. Path of funds: funding wallet (your key) -> routing provider (in transit) -> your Base account (your key) -> Peer escrow (contract). Fees along it: source network fee, route fee (quoted up front), Base gas for the approval and the deposit. ## Install Requires Node.js 22 or newer. ```sh npm install -g payhumans-ai-cli payhumans --version ``` ## Quickstart ```sh npm install -g payhumans-ai-cli # 1. What can be paid, and what can fund it payhumans platforms payhumans routes # 2. Preview an order. Nothing is signed or sent. payhumans deposit create --platform revolut --recipient '' \ --amount 5 --currency USD --rate 0.98 # 3. Same command with an ID, a source spend cap and --yes payhumans deposit create --platform revolut --recipient '' \ --amount 5 --currency USD --rate 0.98 \ --operation-id invoice-1042 --max-source-spend 5.5 --yes # 4. Watch it, then take back whatever was not claimed payhumans deposit show payhumans deposit withdraw --id \ --operation-id invoice-1042-withdraw --yes ``` Results are JSON on stdout. Errors are JSON on stderr with a non-zero exit code. Every command that spends is a preview until you pass `--yes`. ## Wallets and keys The agent uses a wallet it already controls. There is no account to create, no API key, and no hosted wallet. Provide one signing key through your secret manager, for the chain you fund from. | Variable | Purpose | | --- | --- | | `PAYHUMANS_SOLANA_KEY` | Solana signing key for a Solana funding wallet: a base58 secret or a Solana CLI JSON array. | | `PAYHUMANS_SOLANA_KEY_FILE` | Path to a file holding that key, instead of the variable above. | | `PAYHUMANS_EVM_KEY` | 0x-prefixed private key for an EVM funding wallet (Ethereum, Base, Arbitrum, Optimism, Polygon). Also owns the order when funding with bitcoin. PAYHUMANS_PRIVATE_KEY is accepted as an alias. | | `PAYHUMANS_EVM_KEY_FILE` | Path to a file holding that key. PAYHUMANS_PRIVATE_KEY_FILE is accepted as an alias. | | `PAYHUMANS_STATE_DIR` | Optional. Where operation journals are kept. Defaults to ~/.payhumans/operations. Keep and back up this directory: it is what protects a retry from paying twice. | | `PAYHUMANS_SOLANA_RPC_URL` | Optional. Your own Solana RPC endpoint. | | `PAYHUMANS_ESCROW_RPC_URL` | Optional. Your own Base RPC endpoint. | | `PAYHUMANS_RPC_` | Optional. Your own RPC endpoint for one EVM chain, for example PAYHUMANS_RPC_1 for Ethereum. | | `PAYHUMANS_EVM_RPC_URL` | Optional. Your own RPC endpoint for whichever EVM source chain you selected. | | `PAYHUMANS_RELAY_API_KEY` | Optional. Your own Relay API key. | | `PAYHUMANS_NEAR_INTENTS_TOKEN` | Optional. Your own NEAR Intents token, used only by the bitcoin route. | Never put a key in a command argument, a prompt, a log or a website. The browser login on payhumans.ai is optional, exists for people recovering a claim made in the browser, and is never needed by an agent. ## Balances ```sh payhumans wallet # USDC on Solana (default) payhumans wallet --source-chain solana --source-asset SOL payhumans wallet --source-chain ethereum --source-asset ETH ``` `payhumans wallet` (alias `balances`) prints the balance of the asset you fund from, and your Base account with its USDC and ETH. - The funding wallet needs the asset itself plus that chain's network fee: a little SOL on Solana, a little ETH on an EVM chain. - The Base account needs a little ETH for the approval and the deposit. When you fund from another chain the CLI buys a small amount through the route if the balance is low. When you fund from Base, or with bitcoin, it must already hold at least 0.00002 ETH. ## Platforms and recipients An order names one payment platform, one fiat currency and one recipient. Ask the CLI what is supported rather than hard-coding it. Three different sets, do not confuse them: 12 platforms are in the Peer catalog and can be named in an order. 10 of them can be filled in the Peer mobile app (Venmo, Revolut, Cash App, Wise, PayPal, Zelle, Chime, Monzo, UPI and Alipay). 8 of those can be chosen in the app's order alerts (Venmo, Revolut, Cash App, Wise, PayPal, Zelle, Chime and Monzo). ```sh payhumans platforms # payment platforms, currencies, recipient rules payhumans routes # crypto sources the CLI can fund from payhumans routes --live # plus what the routing providers advertise right now ``` Recipient rules as of 2026-10-04 (`payhumans platforms` is the authority): | Platform | --platform | Recipient is a | Before the first order | Currencies | Fillable in Peer app | App alerts | | --- | --- | --- | --- | --- | --- | --- | | Venmo | `venmo` | Venmo username | Checked against the live Venmo profile when the order is created. | USD | Yes | Yes | | Revolut | `revolut` | Revtag | Checked against the public Revolut profile when the order is created. | USD EUR GBP SGD NZD AUD CAD JPY HKD MXN SAR AED THB TRY PLN CHF ZAR CNY CZK DKK HUF NOK RON SEK | Yes | Yes | | Cash App | `cashapp` | Cashtag, without the leading $ | The Cash App profile must be public and resolve. | USD | Yes | Yes | | Wise | `wise` | Wisetag, without the leading @ | A recipient Peer has not seen before must verify the account once. The recipient does this themselves; an agent cannot. An already verified recipient can be reused. | USD CNY EUR GBP AUD NZD CAD AED CHF ZAR SGD ILS HKD JPY PLN TRY IDR KES MYR MXN THB VND UGX CZK DKK HUF INR NOK PHP RON SEK | Yes | Yes | | PayPal | `paypal` | PayPal.me username, not an email | Same one-time verification as Wise. The recipient must be a personal PayPal account. | USD EUR GBP SGD NZD AUD CAD | Yes | Yes | | Zelle | `zelle` | Enrolled email address, lowercase | Format check only. Nothing confirms the email is enrolled with Zelle, so confirm it with the recipient. | USD | Yes | Yes | | Chime | `chime` | $ChimeSign, lowercase, with the leading $ | Format check only. Confirm the ChimeSign with the recipient. | USD | Yes | Yes | | Monzo | `monzo` | Monzo.me username | Checked against the Monzo profile when the order is created. | GBP | Yes | Yes | | Mercado Pago | `mercadopago` | 22-digit CVU | Checksum validation only. | ARS | No | No | | UPI | `upi` | VPA such as name@bank, lowercase | Format check only. In the Peer app the payer proves the payment through Amazon Pay: person-to-person UPI from a linked bank account. UPI Lite and merchant payments are not supported. | INR | Newer versions | No | | Alipay | `alipay` | Alipay account email | Same one-time verification as Wise. | CNY | Newer versions | No | | X Money | `xmoney` | X username, without the leading @ | Format check only. Nothing confirms the account exists or has X Money enabled, so confirm it with the recipient. | USD | No | No | "Fillable in Peer app" says whether people can fill orders on that platform in the Peer mobile app. "Newer versions" (UPI and Alipay) means support is in the app's current source but has not been confirmed in the store build. An order on a platform marked "No" (Mercado Pago and X Money) can be created, but cannot be filled through the current Peer mobile app; other Peer surfaces may differ. None of this has been observed on a production device. Validate and register a recipient before funding anything. Registering stores the recipient's payment details with Peer so the app can show them to whoever claims; it moves no crypto. `deposit create --yes` registers for you if you skip it. ```sh payhumans recipient validate --platform revolut --recipient '' payhumans recipient register --platform revolut --recipient '' # preview payhumans recipient register --platform revolut --recipient '' --yes payhumans recipient show --platform revolut --hash '' ``` Validation checks the format, and on some platforms that the profile exists. It never proves the handle belongs to the person you mean to pay. Wise, PayPal and Alipay: a recipient Peer has not seen before must prove they own the account, once, in a desktop browser with the Peer extension. Wise: https://app.peer.xyz/sell/wise . PayPal: https://app.peer.xyz/sell/paypal . Alipay and the general entry point: https://app.peer.xyz/sell?tab=advanced (guide: https://docs.peer.xyz/guides/for-sellers/provide-liquidity-sell-usdc). An agent cannot do this for them. Until it is done the CLI stops with `RECIPIENT_REGISTRATION_REQUIRED` before any funds move. A recipient who is already verified can be reused. PayPal recipients must be personal accounts. ## Funding routes Choose the source with `--source-chain` and `--source-asset`. The default is USDC on Solana. The CLI converts to USDC on Base through a routing provider (Relay) and refuses a source it cannot route before anything is sent. USDC already sitting in your Base account is used first; only the shortfall is routed. | Fund with | On | Status | Notes | | --- | --- | --- | --- | | USDC | Solana | Tested on mainnet | Mainnet deposits 5962, 5968 and 5970 on October 2, 2026: funded, created, withdrawn and returned to the Solana wallet. | | USDC | Base | Listed, not tested | Already the settlement asset, so there is no conversion and no route fee. The wallet must already hold ETH on Base for gas. | | USDC | Ethereum, Arbitrum, Optimism, Polygon | Listed, not tested | Bridged to USDC on Base by the routing provider. | | ETH | Ethereum, Base | Tested on mainnet | Independent installed-CLI tests funded 5 USDC each: Ethereum deposit 6020 and Base deposit 6021 on October 4. This verifies funding, not fiat payment. | | ETH | Arbitrum, Optimism | Listed, not tested | Swapped to USDC on Base by the routing provider. | | SOL | Solana | Tested on mainnet | Native SOL funded 5 USDC in mainnet deposit 6019 on October 4. The unused escrow was withdrawn to its Base owner. | | BTC (native) | Bitcoin | Tested on mainnet | An external native Bitcoin wallet funded 10 USDC in deposit 6022 through NEAR Intents on October 4; the unused escrow was withdrawn on Base. You send BTC yourself once. Provider minimums vary and Bitcoin network fees are extra. The CLI never holds a Bitcoin key; wrapped bitcoin is not accepted. | Status meanings: - Tested on mainnet: PayHumans funded, created and withdrew a real deposit through this route. - Listed, not tested: Implemented in the CLI. PayHumans has not yet funded a deposit through it. A preview that succeeds is a quote, not a funded test. - Not available: The CLI rejects this source. Nothing is sent. - A listed route still needs a live quote. Availability, minimum size and fees are decided when you preview. - Native bitcoin works differently. The CLI holds no Bitcoin key. It returns a deposit address, an exact amount and a deadline from the provider (NEAR Intents); you send BTC once from your own wallet, then resume the operation. It needs `--refund-address`, an EVM key to own the order, and ETH on Base for gas. The provider's minimum varies: a quote for a 5 USDC order was rejected and one for 10 USDC succeeded. Your Bitcoin network fee is extra, and a failed route may refund less than you sent. Never send after the deadline or a second time. Native BTC funded 10 USDC in mainnet deposit 6022 on October 4; the unused funds were recovered on Base. Fiat payment remains unverified. - Wrapped bitcoin (WBTC, cbBTC and similar) is a different asset and is not accepted. ## Preview and cost Run `deposit create` without `--yes`. With a key configured, the CLI checks the recipient's format, fetches a live route quote and prints the plan. With no key it prints the terms only. Either way nothing is registered, signed or sent. ```sh # Preview: prints the plan as JSON. Nothing is signed or sent. payhumans deposit create --platform revolut --recipient '' \ --amount 5 --currency USD --rate 0.98 ``` ```sh # The same order, funded from ETH on Ethereum instead payhumans deposit create --platform revolut --recipient '' \ --amount 5 --currency USD --rate 0.98 \ --source-chain ethereum --source-asset ETH ``` What an order costs you: - The rate. `--amount` is the gross USDC in escrow and `--rate` is fiat sent per USDC of escrow claimed. At 0.98, a claim of 5 USDC asks for 4.90 in fiat, rounded up to a cent. Peer's fees are then taken from that USDC, so the person receives a little less than 5. Preview field: `fiatForFullDeposit`. - Route fee. The routing provider's charge to convert your asset to USDC on Base. Zero when you fund with USDC on Base. Preview field: `routes.funding`. - Network fees. Gas on the source chain, and on Base for the approval and deposit. Preview fields: `routes.gas`, `caps`. `totalSourceInput` is what the route takes from your funding wallet, in the source asset, with the route's fees included. Network gas you pay directly is on top of it. Peer's own fees come out of the USDC the person receives, not out of your wallet. Limits you set. The CLI stops before signing if a quote exceeds one: - `--max-source-spend`: What the route may take from your funding asset, in that asset's units: the amount converted, fees priced into the route, and any Base gas the route buys. Required with --yes. For USDC sources, --max-spend is accepted as an alias and also caps the deposit itself. - `--max-route-fee-usd`: The routing provider's service and relay fees, in USD. Default 2. - `--slippage-bps`: Swap slippage tolerance. Default 50, range 0 to 100. - `--max-source-gas`: Execution gas on the source chain. Default 0.002 SOL or 0.001 ETH. A ceiling, not an amount held in reserve. - `--max-base-gas`: Execution gas on Base for the approval and deposit. Default 0.0001 ETH. Costs none of these limits cover: - L1 data fees that Base and other rollups add on top of execution gas. - Solana account rent. - The Bitcoin network fee on a payment you send from your own wallet. Leave a small margin for those. Each limit covers one order; keep your own budget across orders. ## Create an order Repeat the command you previewed and add an operation ID you choose, a source spend limit, and `--yes`. ```sh # Same command, plus an operation ID, a source spend cap and --yes. payhumans deposit create --platform revolut --recipient '' \ --amount 5 --currency USD --rate 0.98 \ --operation-id invoice-1042 --max-source-spend 5.5 --yes ``` In order, the CLI then: 1. Validates and registers the recipient, and prepares the deposit. No funds have moved yet. 2. Runs the route: your asset becomes USDC in your Base account. 3. Approves the escrow for exactly the order amount. 4. Creates the deposit and reads its ID from the transaction receipt. 5. Turns off Peer's dispute protection for the order's platform. That removes the stake a person would otherwise have to post to claim, and nothing else: Peer's other eligibility rules still apply. You accept the risk of a payment being reversed after release. Pass `--require-stake` to keep it on. The result includes `depositId`, `compositeDepositId`, `transactionHash`, each route's `requestId` and status, and a `claimUrl`. It also repeats: the deposit is created; fiat has not been paid or proven by this action. Orders several people can fill: `--min` and `--max` set the smallest and largest single claim, in gross USDC. By default a claim can be anything from 1 USDC up to the whole order. Each claim is a separate fiat payment, so the recipient may receive several smaller payments instead of one. ```sh # One order that several people can fill, 1 to 5 USDC at a time payhumans deposit create --platform revolut --recipient '' \ --amount 20 --currency USD --rate 0.98 --min 1 --max 5 ``` All flags on `deposit create`: | Flag | Needed | Meaning | | --- | --- | --- | | `--platform ` | Always | Payment platform, from payhumans platforms. | | `--recipient ` | Always | Who gets the fiat, in that platform's identifier format. | | `--amount ` | Always | USDC to put in escrow. This is the gross amount, before Peer's fees. | | `--currency ` | Always | Fiat currency the recipient is paid in. | | `--rate ` | Always | Fiat a person sends per USDC of escrow they claim. 0.98 means $4.90 for a 5 USDC claim. Peer's fees then come out of that USDC, so the person receives a little less than they claimed. | | `--source-chain ` | Default solana | Where the funding crypto is: ethereum, base, arbitrum, optimism, polygon, solana or bitcoin. | | `--source-asset ` | Default USDC | ETH, SOL, USDC or BTC, depending on the chain. | | `--min , --max ` | Optional | Smallest and largest single claim. Defaults: 1 USDC (or the full amount if smaller) and the full amount. | | `--operation-id ` | With --yes | Your own unique ID for this payment. Reuse it on every retry: the CLI then resumes the saved operation from its local journal instead of starting a new payment. | | `--max-source-spend ` | With --yes | Most of the source asset the route may take, including fees priced into the route and any Base gas it buys. Network gas you pay directly is not included. For USDC sources, --max-spend is accepted as an alias and also caps the deposit. | | `--max-route-fee-usd ` | Default 2 | Most the routing provider may charge in service and relay fees, in USD. Source network gas is separate. | | `--slippage-bps ` | Default 50 | Swap slippage tolerance, 0 to 100 basis points. | | `--max-source-gas ` | Default 0.002 SOL or 0.001 ETH | Ceiling on source-chain execution gas. Solana account rent and your own Bitcoin transaction fee are not covered by it. | | `--max-base-gas ` | Default 0.0001 | Ceiling on Base execution gas for the approval and deposit. The L1 data fee Base adds can be extra. | | `--require-stake` | Optional | Keep Peer's dispute protection on, so people must post stake to claim. | | `--refund-address ` | Bitcoin only | Your own mainnet Bitcoin address, used if the provider has to refund. A refund can be less than you sent. | | `--yes` | To execute | Sign and send. Without it every command is a preview. | ## Identifiers | ID | Comes from | Use it to | | --- | --- | --- | | `operationId` | You choose it. One per payment; 1 to 80 letters, digits, hyphens or underscores. | Retry or resume. While its local journal exists, the same ID resumes the saved operation instead of starting a new payment. | | `depositId` | The escrow contract, when the deposit is created. | Read status and withdraw. | | `compositeDepositId` | The escrow address and deposit ID joined by an underscore. | Refer to the order unambiguously in Peer's APIs and app. | | `intent hash` | Each claim a person makes. Listed under intents in deposit show. | Tell claims apart and see which were fulfilled. | | `requestId` | The routing provider, one per swap or bridge. | Reconcile a slow or failed route before retrying. | ## Status and partial fills ```sh payhumans deposit show payhumans deposit list --owner '' # Or derive the owner from your configured source wallet: payhumans deposit list --source-chain ethereum --source-asset ETH ``` `deposit show` needs no key. It reports where the order's USDC is and lists every claim under `intents`. Top-level balances are decimal USDC; nested intent amount fields use USDC base units (6 decimals, so 1000000 means 1 USDC). The response labels these fields in `intentAmountUnits`. `disputeProtection` reports current per-platform policy and stake requirements, or null when the setting is unknown or the deposit is closed. Do not interpret null as disabled. | Field | Meaning | | --- | --- | | `funded` | USDC the agent put into the order. | | `available` | USDC nobody has claimed. Open to be claimed, or withdrawn by the agent. | | `reserved` | USDC held for a person's active claim. Locked until that claim is fulfilled, cancelled, or expires and is cleared. | | `fulfilled` | USDC released from escrow against verified fiat payments. Gross: the people who paid received this less Peer's fees. | | `withdrawn` | USDC the agent took back. | funded = available + reserved + fulfilled + withdrawn. - A claim is not a payment. A claim in the `SIGNALED` state is a reservation. Only `FULFILLED` means the escrow released USDC against a verified fiat payment. - Fiat delivered so far is about `fulfilled` multiplied by your rate; each claim's fiat amount is rounded up to a cent. For proof of an individual payment, read that claim's receipt fields under `intents`. - `available` and `reserved` are read from the chain. `funded`, `fulfilled`, `withdrawn` and `intents` come from Peer's indexer and can trail by a short time. If `indexed` is false, the indexed fields are null rather than zero and only the chain values are present. - `deposit list --owner
` includes closed orders from the indexer for the current Base escrow. It is a historical view and may lag onchain liquidity. - On RPC throttling, back off 15–30 seconds. A private Base endpoint can be set with `PAYHUMANS_ESCROW_RPC_URL` or `PAYHUMANS_RPC_8453`; keep credentials in your secret environment. Resume the original operation ID after interrupted execution. - Polling once a minute is plenty. An order is finished when `available` and `reserved` are both zero. ## Expiry and cancellation - A claim reserves USDC for a limited window set by Peer. Its expiry time is on the claim. - The person can cancel a claim they have not paid. The reserved USDC becomes available again. - If the window passes without a valid proof, the claim is no longer valid. Its USDC may still show as reserved until Peer clears the expired claim; after that it can be claimed again or withdrawn. Check the claim's status before acting. - The agent cannot cancel someone else's active claim, and should not try to work around one: that person may already have sent the fiat. - An order itself does not expire. It stays open until it is filled or you withdraw. - If fiat was sent but the proof fails or is late, the escrow does not pay and the fiat cannot be recovered through PayHumans or Peer. ## Recovery and withdrawal An interrupted run: the CLI keeps a local journal in `~/.payhumans/operations` (override with `PAYHUMANS_STATE_DIR`). - Every signed crypto operation writes a journal of its steps there, named by operation ID. Recipient registration moves no crypto and creates no operation journal. - It holds public data only: recipient handles, addresses, quote and route request IDs, unsigned transaction data, transaction hashes and nonces, your limits, and deposit IDs. It never holds private keys. - Retry protection lives in that journal. Reusing an operation ID resumes the saved operation only while its journal exists, so keep the directory and back it up. If it is deleted, the CLI no longer knows what was already sent. - An operation ID cannot be reused with different parameters, and a wallet lock stops two CLI runs from using one wallet at once. Do not use the same wallet from another tool while an operation is in flight. - A different operation ID is a different payment. Do not answer a timeout by choosing a new ID: inspect the operation and resume it. If a run crashes or a route is slow, resume it: ```sh payhumans operations list payhumans operations show invoice-1042 payhumans operations resume invoice-1042 # preview payhumans operations resume invoice-1042 --yes ``` Take back unclaimed funds: `deposit withdraw` removes available USDC from the order (all of it unless you pass `--amount`) and sends it to your Base account. It never touches reserved USDC and never cancels a claim. The command signs with the wallet selected by `--source-chain` and `--source-asset` (default: the Solana key), so pass the same source you funded with. ```sh payhumans deposit withdraw --id # preview payhumans deposit withdraw --id \ --operation-id invoice-1042-withdraw --yes # Funded from an EVM wallet? Name it, so the CLI signs with that key. payhumans deposit withdraw --id \ --source-chain ethereum --source-asset ETH \ --operation-id invoice-1042-withdraw --yes ``` Send it home: after a withdrawal the USDC is in your Base account. With an EVM key, that is already your wallet. With a Solana key, `return` routes it back to the same Solana wallet as USDC; `--min-receive` is required and bounds fees and slippage. There is no route back to bitcoin. ```sh payhumans return --amount 5 # preview, shows minimum received payhumans return --amount 5 --min-receive 4.8 \ --operation-id invoice-1042-return --yes ``` Remove the stake requirement: if dispute protection is still on for an order, people must post stake to claim it. `deposit open-claims` turns it off for one platform on one order. It removes that stake requirement only; Peer's other eligibility rules still apply. ```sh payhumans deposit open-claims --id --platform revolut \ --operation-id invoice-1042-open --yes ``` ## Errors A failed command exits non-zero and writes one JSON object to stderr: `{"error": {"code": "...", "message": "...", "next": "..."}}`. Stdout carries only successful results. - `OPERATION_NOT_FOUND`: No saved journal exists for that ID in the current state directory. Run operations list and confirm PAYHUMANS_STATE_DIR points to the original journal. If funds may already have moved, reconcile the original transaction before creating a new operation. - `INVALID_ARGUMENT`: A flag is missing or malformed. Nothing was sent. - `RECIPIENT_REGISTRATION_REQUIRED`: The recipient must complete Peer's one-time verification. Nothing was sent. Retry the same operation ID afterwards. - `REQUEST_FAILED`: Anything else. Read message. If a run with --yes had started, inspect the operation before retrying. ## How people fill orders An order is an ordinary Peer deposit, so people fill it in the Peer mobile app, from its P2P tab or Buy USDC flow. From their side they are buying USDC at your rate by paying your recipient. There is no PayHumans account. This workflow is taken from the app's current source; it has not been observed on a production device. 1. They choose a currency and a payment platform they already use. 2. The app lists open orders by price. They pick one and claim some or all of it. 3. They send the exact fiat amount to the recipient shown, from their own account. 4. They verify the payment inside the app. The escrow releases the USDC to them, less Peer's fees. Nobody is guaranteed to see your order. An order can appear in the Peer app once Peer has indexed it, if it passes the app's filters and eligibility rules: a platform and currency the app supports, enough unreserved USDC, a usable exchange rate, a minimum order value (about $1 by default), and the person's own platform, amount and price filters. The app's alerts for new orders are opt-in, limited to 8 platforms (Venmo, Revolut, Cash App, Wise, PayPal, Zelle, Chime and Monzo), filtered by price and by a minimum size that defaults to $25, and rate-limited. Delivery has not been verified. A small order can sit unclaimed. In the app, UPI payments are proved through Amazon Pay (person-to-person UPI from a linked bank account; not UPI Lite or merchant payments), and Zelle payments from Bank of America or Citi. - Guide for people, with download links: https://payhumans.ai/earn - Get the Peer app: https://mobile.peer.xyz/onboard (App Store: https://apps.apple.com/us/app/peer-pay-earn/id6749191100 ; Google Play: https://play.google.com/store/apps/details?id=com.zkp2p.mobile.dev) - The CLI's `claimUrl` (`https://payhumans.ai/earn?deposit=`) opens the claim page, which shows that order's live terms read from the escrow. Share it so a person can check the recipient, amount and rate. ## Verification limits Payment verification is done by Peer's verification service and escrow contract, not by PayHumans. - Only supported platforms and currencies can be proved, and support differs between them. - The proof must match the claim: recipient, amount, currency, and a payment made after the claim. - A proof shows a payment left the person's account. It does not cover later reversals, disputes or holds by the payment platform. - Changes on a payment platform can temporarily break verification for it. ## Project status as of October 4, 2026 Run on mainnet with real funds: - Native SOL, Ethereum ETH and Base ETH each funded a 5 USDC Revolut order on mainnet: deposits 6019, 6020 and 6021. Independent Astra and Claude testers used the published CLI for the Ethereum and Base runs. - Native Bitcoin funded 10 USDC in deposit 6022 through an external Bitcoin wallet and NEAR Intents. Funding and creation completed; unused funds were recovered as Base USDC. - A controlled unpaid 1 USDC claim on deposit 6020 left 4 USDC available. The CLI rejected an over-withdrawal and recovered only those 4 USDC. After we cancelled our own unpaid claim, the remaining 1 USDC was recovered. No fiat was sent. - A 5 USDC withdrawal from deposit 6019 returned 4.763997 USDC to the original Solana wallet after routing costs; a stricter minimum-receive preview rejected the quote safely. - All four new orders matched the current Peer mobile orderbook APIs and recipient checks. Completed operation retries returned the same deposit instead of creating another. - Earlier Solana USDC tests covered deposits 5962, 5968 and 5970, browser claim recovery and returning unused funds to Solana. Not yet verified: - A real fiat payment followed by payment proof and a USDC payout has not been verified in these PayHumans tests. - Taking a PayHumans order inside the Peer mobile app on a physical device, and delivery of its push alerts. - Arbitrum and Optimism ETH, EVM USDC source routes and direct Base USDC funding remain implemented but not funded-tested in this release. PayHumans.ai is an independent project. It began as a website prototype on March 27, 2026. The CLI, the live escrow integration and the current site were built from October 2, 2026 onward. The escrow contracts, payment verification, SDKs and mobile app are Peer's existing infrastructure, not new work by PayHumans. Routing is provided by Relay, and by NEAR Intents for the external-wallet native bitcoin route.