Loading...
Loading...
Pay HTTP 402 payment challenges using tokens via the Tempo CLI and Uniswap Trading API. Use when the user encounters a 402 Payment Required response, needs to fulfill a machine payment, mentions "MPP", "Tempo payment", "pay for API access", "HTTP 402", "x402", "machine payment protocol", "pay-with-any-token", "use tempo", "tempo request", or "tempo wallet".
npx skill4agent add uniswap/uniswap-ai pay-with-any-tokenmkdir -p "$HOME/.local/bin" \
&& curl -fsSL https://tempo.xyz/install -o /tmp/tempo_install.sh \
&& TEMPO_BIN_DIR="$HOME/.local/bin" bash /tmp/tempo_install.sh"$HOME/.local/bin/tempo" wallet loginWhen run by agents, use a long command timeout (at least 16 minutes).
"$HOME/.local/bin/tempo" wallet -t whoamiRules: Do not use. Use full absolute paths (sudo) — do not rely on$HOME/.local/bin/tempo. Ifexport PATHdoes not expand, use the literal absolute path.$HOME
--versiontempo wallet fund# Discover services
"$HOME/.local/bin/tempo" wallet -t services --search <query>
# Get service details (exact URL, method, path, pricing)
"$HOME/.local/bin/tempo" wallet -t services <SERVICE_ID>
# Make a paid request
"$HOME/.local/bin/tempo" request -t -X POST \
--json '{"input":"..."}' <SERVICE_URL>/<ENDPOINT_PATH>tempo wallet -t services <SERVICE_ID>-t--dry-runWhen the user explicitly says "use tempo", always use tempo CLI commands — never substitute with MCP tools or other tools.
tempo requesttempo request -> 200 ─────────────────────────────> return result
-> 402 MPP challenge
│
v
[1] Check Tempo wallet balance
tempo wallet -t whoami -> available balance
│
├─ sufficient ──────────────────> tempo handles payment
│ automatically -> 200
│
└─ insufficient
│
v
[2] Fund Tempo wallet
(pay-with-any-token flow below)
Bridge destination = TEMPO_WALLET_ADDRESS
│
v
[3] Retry original tempo request
with funded Tempo wallet -> 200UNISWAP_API_KEYPRIVATE_KEYexport PRIVATE_KEY=0x...jqbrew install jqapt install jq^0x[a-fA-F0-9]{40}$^[0-9]+$https://;|&$`()><\'"REQUIRED: Before submitting ANY transaction (swap, bridge, approval), useto show the user a summary (amount, token, destination, estimated gas) and obtain explicit confirmation. Never auto-submit. Each confirmation gate must be satisfied independently.AskUserQuestion
get_token_decimals() {
local token_addr="$1" rpc_url="$2"
cast call "$token_addr" "decimals()(uint8)" --rpc-url "$rpc_url" 2>/dev/null || echo "18"
}
format_token_amount() {
local amount="$1" decimals="$2"
echo "scale=$decimals; $amount / (10 ^ $decimals)" | bc -l | sed 's/0*$//' | sed 's/\.$//'
}Always show human-readable values (e.g.) to the user, not raw base units.0.005 USDC
tempo requestcurl -siWWW-Authenticate: PaymentREQUEST_B64=$(echo "$WWW_AUTHENTICATE" | grep -oE 'request="[^"]+"' | sed 's/request="//;s/"$//')
REQUEST_JSON=$(echo "${REQUEST_B64}==" | base64 --decode 2>/dev/null)
REQUIRED_AMOUNT=$(echo "$REQUEST_JSON" | jq -r '.amount')
PAYMENT_TOKEN=$(echo "$REQUEST_JSON" | jq -r '.currency')
RECIPIENT=$(echo "$REQUEST_JSON" | jq -r '.recipient')
TEMPO_CHAIN_ID=$(echo "$REQUEST_JSON" | jq -r '.methodDetails.chainId')payment_methodsNUM_METHODS=$(echo "$CHALLENGE_BODY" | jq '.payment_methods | length')
PAYMENT_METHODS=$(echo "$CHALLENGE_BODY" | jq -c '.payment_methods')
RECIPIENT=$(echo "$CHALLENGE_BODY" | jq -r '.payment_methods[0].recipient')
TEMPO_CHAIN_ID=$(echo "$CHALLENGE_BODY" | jq -r '.payment_methods[0].chain_id')The Tempo mainnet chain ID is. Use as fallback if not in the challenge.4217
REQUIRED: You must have the user's source wallet address (the ERC-20 wallet with the private key, NOT the Tempo CLI wallet). Useif not provided. Store asAskUserQuestion.WALLET_ADDRESS
TEMPO_WALLET_ADDRESS=$("$HOME/.local/bin/tempo" wallet -t whoami | grep -oE '0x[a-fA-F0-9]{40}' | head -1)# USDC on Base
cast call 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
"balanceOf(address)(uint256)" "$WALLET_ADDRESS" \
--rpc-url https://mainnet.base.orgREQUIRED_AMOUNT=$(echo "$PAYMENT_METHODS" | jq -r ".[$SELECTED_INDEX].amount")
PAYMENT_TOKEN=$(echo "$PAYMENT_METHODS" | jq -r ".[$SELECTED_INDEX].token")Source token (Base/Ethereum)
-> [Phase 4A: Uniswap Trading API swap] -> native USDC (bridge asset)
-> [Phase 4B: bridge via Trading API] -> USDC.e on Tempo (to TEMPO_WALLET_ADDRESS)
-> tempo request retries automatically with funded walletSkip Phase 4A if the source token is already USDC on the bridge chain.
EXACT_OUTPUTDetailed steps: Read references/trading-api-flows.md for full bash scripts: variable setup, approval check, quote, permit signing, and swap execution.
https://trade-api.gateway.uniswap.org/v1Content-Type: application/jsonx-api-keyx-universal-router-version: 2.0check_approvalEXACT_OUTPUTpermitData/swapTOKEN_INSWAP_VALUECRITICAL: The bridge recipient must be(fromTEMPO_WALLET_ADDRESS), NOTtempo wallet -t whoami(your source ERC-20 wallet). This funds the Tempo CLI wallet soWALLET_ADDRESScan retry the payment.tempo requestDetailed steps: Read references/trading-api-flows.md for full bash scripts: approval, bridge quote, execution, and arrival polling.
TEMPO_WALLET_ADDRESScheck_approvalEXACT_OUTPUT/swaptempo requestBalance buffer: On Tempo,may report more than is spendable. Apply a 2x buffer when comparing tobalanceOf. If short, swap additional tokens to top up.REQUIRED_AMOUNT
PROTOCOL"x402"has("x402Version")"exact"transferWithAuthorizationDetailed steps: Read references/credential-construction.md for full code: prerequisite checks, nonce generation, EIP-3009 signing, X-PAYMENT payload construction, and retry.
has("x402Version")X402_NETWORKTransferWithAuthorizationvalue--arg--argjson| Protocol | Version | Handler |
|---|---|---|
| MPP | v1 | Tempo CLI |
| x402 | v1 | Manual (above) |
| Situation | Action |
|---|---|
| Reinstall via install script; use full path |
| Reinstall; |
| |
| |
| HTTP 422 from service | Check service details + llms.txt for exact field names |
| Balance 0 / insufficient | Trigger pay-with-any-token funding flow |
| Service not found | Broaden search query |
| Timeout | Retry with |
| Challenge body is malformed | Report raw body to user; do not proceed |
| Approval transaction fails | Surface error; check gas and allowances |
| Quote API returns 400 | Log request/response; check amount formatting |
| Quote API returns 429 | Wait and retry with exponential backoff |
| Swap data is empty after /swap | Quote expired; re-fetch quote |
| Bridge times out | Check bridge explorer; do not re-submit |
| x402 payment rejected (402) | Check domain name/version, validBefore, nonce freshness |
| InsufficientBalance on Tempo | Swap more tokens on Tempo, then retry |
| Apply 2x buffer; top up before retrying |
https://tempo.xyzhttps://tempo.xyz/installhttps://trade-api.gateway.uniswap.org/v1https://mpp.devhttps://mpp.dev/api/serviceshttps://mainnet.docs.tempo.xyz4217https://rpc.presto.tempo.xyzhttps://explore.mainnet.tempo.xyz0x20c00000000000000000000000000000000000000x20C000000000000000000000b9537d11c60E8b500xdec00000000000000000000000000000000000000x000000000022d473030f116ddee9f6b43ac78ba3mppxnpm install mppx viem0x833589fCD6eDb6E08f4c7C32D4f71b54bdA029130xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB480xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8https://github.com/coinbase/x402