Prompt in → PNG out. Paid via x402 (HTTP 402 + USDC on Base mainnet eip155:8453). No API keys — payment is the auth. White-label https://x402.chaly.org/images/*.png (hash names, 7-day retention).
Try it free: curl -X POST https://x402.chaly.org/free -H "Content-Type: application/json" -d '{"prompt":"a red cube on a blue table"}' → 202 + pollUrl → your PNG in ~90s. One per IP per day; paid tier unlimited from $0.001/image.
Network eip155:8453 · payTo 0x53406C32dF6e494aFB078279EA3AD752542E5F0f · facilitator https://facilitator.payai.network · servable low:1K · checking health…
| quality:MP | per image | total | served? |
|---|---|---|---|
| low:1K | $0.001 (1000 atomic USDC) | $0.001 × count | ✅ cheapest possible |
| low:2K / 4K, high:* | $0.07 – $0.60 | — | 400 (planned) |
Change via PRICE_TABLE in server.js. Fallback to $0.001 if no traction by tomorrow (operator note).
curl -s https://x402.chaly.org/health | jq .pricing
curl -i -X POST https://x402.chaly.org/generate \
-H "Content-Type: application/json" \
-d '{"prompt":"a red cube on a blue table","count":1}'
# → 402 + PAYMENT-REQUIRED: base64 x402 offer
import {wrapFetchWithPaymentFromConfig} from "@x402/fetch"
import {ExactEvmScheme} from "@x402/evm/exact/client"
import {privateKeyToAccount} from "viem/accounts"
const signer = privateKeyToAccount(process.env.BUYER_PRIVATE_KEY)
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch,
{schemes:[{network:"eip155:8453",client:new ExactEvmScheme(signer)}]})
const res = await fetchWithPayment("https://x402.chaly.org/generate",{
method:"POST", headers:{"Content-Type":"application/json"},
body: JSON.stringify({prompt:"a red cube",count:1,id:"my-key-1"})
})
const {jobId,pollUrl} = await res.json() // 202
let data; while(true){ await new Promise(r=>setTimeout(r,5000))
const pj=await (await fetch(pollUrl)).json()
if(pj.status==="done"){data=pj.result;break}
if(pj.status==="failed") throw new Error(pj.error) }
console.log(data.urls)
POST /generate — x402 paid. Body {prompt, count} or {items:[[prompt,count]]} + quality:low megapixels:1K aspect:1:1|9:16… id → 202 {jobId,pollUrl,estimatedSeconds:85,charged} → poll GET /result/:id every 5s until done {urls,items,images}. 400 on bad tier, 503 if no eligible accounts, 429 if busy.GET /result/:id / GET /jobs/:id — poll. GET /images/:file — PNG.GET /health — pricing + pool_size/eligible + jobs · GET /readyz · GET /livez · GET /metrics · GET /.well-known/x402 (Bazaar) · GET /openapi.json · GET /llms.txt · GET /llms-full.txtMCP server mcp-server.mjs wraps the paid POST + polling as tools image_generate, image_health, image_openapi, image_poll. Wired locally in opencode.jsonc (mcp.x402-image-api). Bazaar via declareDiscoveryExtension {bazaar:true, bodyType:json} — indexed via PayAI facilitator; CDP validate valid:true simulation:accepted. Listed on x402-list / Agent402 / x402scan.
// opencode.jsonc
"mcp": { "x402-image-api": { "command":["node","C:\\Users\\Cali\\Desktop\\opencode-projects\\x402-image-api\\mcp-server.mjs"], "env":{"X402_API_URL":"https://x402.chaly.org"} } }
Pool claim-aware: last_used≥24h · concurrency 3 · worker 600s · Cloudflare Tunnel x402.chaly.org (4 PoPs, QUIC). Backups hourly + on-save to D:\x402-offsite. Health probe every 5m.
payTo on Basescan · x402.org · CDP docs · Bazaar · x402-list · x402scan · Agent402