Verifying $0.05 USDC Payments On-Chain in 40 Lines of Python — No Stripe, No SDK, No KYC A developer built a payment verification system for a French neural TTS API that accepts micro-payments of $0.03–0.05 USDC on the Base network, using only Python's standard library and no payment processor or SDK. The system, based on the x402 pattern, verifies on-chain transactions by scanning logs for USDC transfers to the developer's wallet, enabling AI agents to pay and receive audio in two HTTP calls. Last week I wrote about the French voiceover API that only accepts payment from robots https://dev.to/marcuschen-dev/i-built-a-french-ai-voiceover-api-that-only-accepts-payment-from-robots-435k . Today: the part people actually asked me about — how do you verify a $0.05 payment on-chain with zero payment processor, zero SDK, and zero KYC? The answer: one Python function, ~40 lines, stdlib only. Here's the real production code. My endpoint sells French neural TTS voiceovers for $0.03–0.05 USDC. At that price, Stripe is a non-starter their floor is ~$0.50 per charge and any processor's KYC kills the "robots welcome" model. So payments go through the x402 pattern: client pays USDC on Base, sends me the transaction hash, I verify it myself against a public RPC before delivering. python import json, os, urllib.request WALLET BASE = "0x3f97...D074" where I receive USDC BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" USDC on Base BASE RPC = "https://mainnet.base.org" TRANSFER TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" def rpc method, params : req = urllib.request.Request BASE RPC, data=json.dumps {"jsonrpc": "2.0", "id": 1, "method": method, "params": params} .encode , headers={"Content-Type": "application/json"} with urllib.request.urlopen req, timeout=30 as r: return json.load r .get "result" def verify payment tx hash, min usdc : 1. format sanity if not tx hash.startswith "0x" or len tx hash = 66: return False, "bad hash format" 2. anti-replay: one hash = one delivery if tx hash.lower in load used txs : return False, "tx already used replay " 3. fetch the receipt receipt = rpc "eth getTransactionReceipt", tx hash if not receipt: return False, "tx not found on Base" if receipt.get "status" = "0x1": return False, "tx failed on-chain" 4. scan logs for a USDC Transfer TO my wallet want to = WALLET BASE.lower .replace "0x", "" for log in receipt.get "logs", : if log.get "address", "" .lower = USDC BASE.lower : continue not the USDC contract topics = log.get "topics", if len topics = 3 or topics 0 .lower = TRANSFER TOPIC: continue not a Transfer event to = topics 2 -40: .lower last 20 bytes of topic 2 amount = int log "data" , 16 / 1e6 USDC has 6 decimals if to == want to and amount = min usdc: mark used tx hash return True, f"{amount} USDC received" return False, "no sufficient USDC transfer to me in this tx" That's the whole payment gateway. No web3.py, no API key, no account anywhere. Transfer event from a fake token contract. Only logs from the real USDC contract count. Transfer address,address,uint256 has exactly 3 topics signature + from + to . The recipient is the last 20 bytes of topics 2 . = lets a generous buyer overpay without getting rejected. status == "0x1" If there's no X-Payment-Proof header, the server answers with HTTP 402 yes, the "Payment Required" status code that's been reserved since 1999 and almost never used plus everything a machine needs to pay: { "error": "Payment Required", "amount": 0.05, "currency": "USDC", "network": "BASE", "address": "0x3f97...D074", "proof": "send the Base tx hash in X-Payment-Proof" } An AI agent reading that response has all it needs: chain, token, amount, destination. Pay, retry with the hash, get the MP3. Total round-trip: two HTTP calls. The obvious trade-off: this only works for buyers who already hold USDC on Base — which today means mostly other agents and crypto-natives. That's a feature for now, not a bug. Live endpoint humans get the service card, agents get the 402 dance : curl http://187.77.111.249.sslip.io:8402/ curl -X POST http://187.77.111.249.sslip.io:8402/generate \ -H 'Content-Type: application/json' \ -d '{"product":"ivr","text":"Bonjour et bienvenue"}' → 402 with payment instructions Human portfolio with free audio samples: voixoff-fr.netlify.app https://voixoff-fr.netlify.app Building in public, week 2. Scoreboard so far: 0 sales, 1 working payment rail, ~0 lines of payment-processor code. Previous posts: robot-only API · $0 avatar pipeline