{"schema_version":"1.0","protocolVersion":"0.2.5","name":"CDK Bot","description":"CDK Bot — buy game keys, gift cards, and digital products, built for AI agents. Find the right product and buy it in one API call — zero registration, instant delivery, onchain-verified refunds, 30-day guarantee.","url":"https://api.cdk.bot","version":"1.0.0","contact":{"email":"info@cdk.bot"},"policies":{"terms_of_service":{"url":"https://api.cdk.bot/terms","summary":"No registration required. Payment via USDC on Base chain (x402 protocol). All sales are digital product deliveries. Prices in USD, paid in USDC. Rate limits enforced per IP. Service provided as-is on Cloudflare Workers infrastructure."},"refund_policy":{"url":"https://api.cdk.bot/terms#refund-policy","summary":"Delivery failures (not_delivered) are refunded instantly and automatically. Key-related issues (key_invalid, key_already_redeemed, wrong_product) are verified via supplier and resolved within 24 hours. Submit via POST /refund with order_id, wallet_address, and reason. Approved refunds paid in USDC to original wallet. Refund tx_hash provided as onchain proof.","dispute_window_days":30,"sla":{"not_delivered":"instant (auto-approved)","key_issues":"24 hours (supplier verification)"},"reasons":["key_invalid","key_already_redeemed","wrong_product","not_delivered"]},"privacy":{"url":"https://api.cdk.bot/terms#privacy","summary":"No accounts, no registration, no personal data collected. Transaction data (wallet address, order details) stored for fulfillment and refund purposes. Payment transactions are publicly visible onchain."}},"capabilities":{"mcp":{"url":"https://mcp.cdk.bot/mcp","transport":"streamable-http","description":"MCP server for native tool-use integration. Connect from Claude Desktop, ChatGPT, Cursor, Windsurf, etc. Zero config — just add the URL as a remote MCP server.","tools":["search_games","get_game_details","browse_filters","get_price_quote","confirm_purchase","check_order","request_refund","submit_review"]},"openapi":"/openapi.json","docs":"/docs","health":"/health","payment":{"protocol":"x402","methods":["x402-one-shot-eip3009","USDC-on-Base"],"currencies":["USDC"],"chains":["base"],"one_shot":"Wallet-native agents pay in ONE call: POST /purchase with an `X-PAYMENT` header — a base64 EIP-3009 \"exact\" authorization signed for the accepts[] returned in the 402. A facilitator verifies + settles it on-chain (gasless — you do not pay gas) and the key is delivered in the same response. No tx_hash or quote_id needed. The 402 carries the standard x402 accepts[] for this.","two_step":"Agents without an x402 signer use the 2-step flow (send USDC yourself, then POST tx_hash + quote_id) — always available as a fallback. See quick_start below.","human_payment_url":"https://api.cdk.bot/pay?game_id={id}","human_payment_note":"No-code checkout for people (e.g. an operator testing the API): open this URL — replace {id} with a product id, or omit game_id for the cheapest item. Connect a wallet on desktop or scan the QR with a mobile wallet, pay USDC on Base, key is delivered in the page. Self-custodial, no account.","address":"0x0b321A0F1294431347f98e10a2275F23B11BBfFb","usdc_contract":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","verification":"onchain — ERC-20 Transfer log parsed via viem. Sender wallet extracted from Transfer event and bound to order. quote_id (from 402 response) required with tx_hash as purchase session token — prevents front-running. Payment must use the usdc_contract above — other USDC variants will not be detected.","double_spend_protection":true,"sandbox":{"enabled":true,"chain":"base-sepolia","usdc_contract":"0x036CbD53842c5426634e7929541eC2318f3dCF7e","how_to_use":"Add \"chain\": \"base-sepolia\" to POST /purchase. Payment is verified onchain on Base Sepolia. A mock key (SANDBOX-XXXXX-...) is returned instead of a real product key.","faucets":["https://faucet.circle.com/ — get Sepolia USDC","https://www.alchemy.com/faucets/base-sepolia — get Sepolia ETH for gas"]}}},"auth":{"type":"none","description":"No authentication, API keys, or registration required. Browsing is free. Purchasing uses x402 USDC payment."},"rate_limits":{"browse":{"requests_per_minute":60,"scope":"per-ip"},"purchase":{"requests_per_minute":5,"scope":"per-ip"},"orders":{"requests_per_minute":10,"scope":"per-ip"},"refund":{"requests_per_minute":3,"scope":"per-ip"}},"response_times":{"GET /games":{"p50_ms":50,"p99_ms":200,"description":"Search and filter products"},"GET /games/{id}":{"p50_ms":30,"p99_ms":100,"description":"Single product lookup"},"POST /purchase (402)":{"p50_ms":100,"p99_ms":300,"description":"Get payment instructions"},"POST /purchase (200)":{"p50_ms":1500,"p99_ms":5000,"description":"Verify onchain payment + deliver key. Includes Base RPC call."},"GET /health":{"p50_ms":100,"p99_ms":500,"description":"Liveness and service status"}},"sla":{"target_uptime":"99.5%","infrastructure":"Cloudflare Workers (global edge, ~300 PoPs)","database":"Cloudflare D1 (SQLite on edge)","monitoring":"Cron every 1min: delta sync, polls pending orders, checks DB + supplier health. Public endpoint: GET /health"},"trust":{"payment_address":"0x0b321A0F1294431347f98e10a2275F23B11BBfFb","payment_chain":"base","verification_method":"Onchain ERC-20 Transfer log parsing on Base chain via viem. Amount, recipient, and sender verified before key delivery. Sender wallet extracted from Transfer event and permanently bound to the order — only the sending wallet can retrieve the key or request a refund. quote_id acts as purchase session token (prevents tx_hash front-running). On failure, a structured diagnosis object is returned with code, expected values, found values, and an actionable hint.","payment_error_codes":["tx_not_found — tx hash not found on Base (wrong network?)","tx_failed — tx exists but reverted or is pending","wrong_contract — ERC-20 transfer found but from wrong token contract (not USDC)","wrong_recipient — USDC transfer found but to wrong address","insufficient_amount — correct USDC to correct address, but amount too low","no_transfer_logs — tx has no event logs (looks like native ETH transfer)","no_erc20_logs — tx has logs but no ERC-20 Transfer events"],"double_spend_protection":"Unique constraint on tx_hash in database. Same tx cannot be used for two orders.","source_code":"API logic is inspectable. OpenAPI spec is auto-generated from source.","refund_policy":"POST /refund with order_id, wallet_address, and reason (key_invalid | key_already_redeemed | wrong_product | not_delivered). Requires wallet match. 30-day dispute window from purchase date (dispute_deadline field in order response). Delivery failures (not_delivered) are auto-approved instantly. Key-related issues verified via supplier within 24 hours. Lifecycle: pending → approved → refunded (USDC sent back, refund_tx_hash as onchain proof). Track status via GET /orders/{id}?wallet_address=0x...","refund_verification":"Refund tx_hash is verified onchain — proves USDC was actually returned to buyer wallet on Base chain.","live_stats":"GET /health → trust object with orders_fulfilled, fulfillment_rate, refund_rate, avg_delivery_time_seconds — all computed from real order data.","price_transparency":"Every product includes marketplace_offers[] with live prices from other sources. Compare CDK Bot pricing against the open market in a single API call — no scraping needed.","known_limitations":["Onchain verification adds ~1-3s latency to purchase completion"]},"endpoints":{"health":{"method":"GET","path":"/health","auth":"none","description":"Service liveness, latency, catalog stats"},"games":{"method":"GET","path":"/games","auth":"none","description":"Search/filter products with pagination. Params: q, platform, device, region, language, product_type (game|dlc|gift_card), page, limit. Each item carries marketplace_offers[] (cheapest live market offer per source, in USD) so an agent can rank by total cost without follow-up calls. Returns search_hint when results are broad or empty."},"game_match":{"method":"GET","path":"/games/match","auth":"none","description":"Smart product match — returns ONE best_match + alternatives + explanation. Params: title (required), platform/device/region/language (optional). Use this when you know what product you want and need the right variant. Response includes available_platforms, available_devices, available_regions."},"game_details":{"method":"GET","path":"/games/{id}","auth":"none","description":"Single product details with price, product_type, availability (in_stock), device, language_coverage, languages, language_note, activation_details, and market pricing. Includes marketplace_offers[] = cheapest current market offer per source (in USD) so an agent can see live market prices. product_type: \"game\" | \"dlc\" | \"gift_card\". language_coverage: \"full\" = Multilanguage, \"specific\" = only listed languages, \"unknown\" = no data, \"not_applicable\" = gift cards/prepaid."},"platforms":{"method":"GET","path":"/platforms","auth":"none","description":"Available platform (storefront) names for filtering"},"devices":{"method":"GET","path":"/devices","auth":"none","description":"Available target device names for filtering (PC, PS4, PS5, Xbox One, Xbox Series X|S, Nintendo Switch, etc.). Device = hardware, platform = storefront."},"regions":{"method":"GET","path":"/regions","auth":"none","description":"Available region names for filtering"},"languages":{"method":"GET","path":"/languages","auth":"none","description":"Available language codes for filtering. Use with ?language= param on /games and /games/match."},"product_types":{"method":"GET","path":"/product-types","auth":"none","description":"Available product types with counts. Types: game (base games + editions), dlc (requires base game), gift_card (gift cards, prepaid codes, subscriptions, in-game currency)."},"purchase":{"method":"POST","path":"/purchase","auth":"x402-usdc","description":"Buy a product key. ONE-SHOT: POST with an X-PAYMENT header (signed EIP-3009 \"exact\" authorization for the 402 accepts[]) → facilitator settles gaslessly → key, in one call. TWO-STEP: POST without tx_hash → 402 with payment details + quote_id (price locked 5 min); send USDC yourself; POST again with tx_hash + quote_id → verify + deliver key. If quote expired → 410 with fresh quote and new quote_id."},"orders":{"method":"GET","path":"/orders/{id}","auth":"none","description":"Order status. Pass wallet_address to retrieve key_code."},"receipt":{"method":"GET","path":"/orders/{id}/receipt","auth":"none","description":"Structured purchase receipt for completed orders. Pass wallet_address. Returns seller info, item details, payment proof (tx_hash)."},"refund":{"method":"POST","path":"/refund","auth":"none","description":"Submit refund claim with order_id + wallet_address"},"reviews":{"method":"POST","path":"/reviews","auth":"none","description":"Submit a purchase review (rating 1-5 + optional comment). One review per order. Requires order_id + wallet_address (must match the order)."},"game_reviews":{"method":"GET","path":"/reviews/{game_id}","auth":"none","description":"Public aggregate rating (count + average) for a product."},"openapi":{"method":"GET","path":"/openapi.json","auth":"none","description":"OpenAPI 3.1 spec (machine-readable)"},"docs":{"method":"GET","path":"/docs","auth":"none","description":"Swagger UI (human-readable)"}},"quick_start":{"overview":"x402 protocol, two ways to pay. ONE-SHOT (wallet-native agents): POST /purchase with an X-PAYMENT header — a signed EIP-3009 \"exact\" authorization for the accepts[] in the 402 — and a facilitator settles it gaslessly and returns the key in one call (no tx_hash, no quote_id). TWO-STEP (any agent): POST /purchase → 402 with amount/address/usdc_contract/quote_id (price locked 5 min) → send USDC on Base → POST again with tx_hash + quote_id. If a quote expires → 410 with a fresh quote.","product_search":{"note":"Two search endpoints available. Use /games/match when you know what you want (returns best match). Use /games when browsing or scanning multiple options.","match":"GET /games/match?title=GTA+V&platform=Steam — returns best_match, alternatives, available_platforms, explanation","browse":"GET /games?q=gta&platform=Steam — paginated list with search_hint"},"agent_one_shot":{"description":"BEST UX — wallet-native agent that can sign an EIP-3009 authorization (e.g. an x402 client like Bankr). One call, gasless (the facilitator pays gas).","steps":["GET /games/match?title=... — find the best matching product","POST /purchase {\"game_id\":\"...\"} — receive 402 with accepts[] (standard x402 \"exact\" requirements: payTo, asset, maxAmountRequired, network)","Sign an EIP-3009 transferWithAuthorization for accepts[0], base64-encode {x402Version,scheme,network,payload:{signature,authorization}}, and POST /purchase {\"game_id\":\"...\"} with it as the X-PAYMENT header — receive the product key in the same response. No tx_hash, no quote_id."],"total_http_calls":2,"note":"You sign; the facilitator settles on-chain and pays gas. This is the flow a Bankr `bankr x402 call` agent uses."},"agent_with_wallet":{"description":"Agent has a private key and can send USDC directly (2-step fallback — use this if you cannot construct an x402 X-PAYMENT).","steps":["GET /games/match?title=...&platform=... — find the best matching product","POST /purchase {\"game_id\":\"...\"} — receive 402 with amount, address, usdc_contract, quote_id (price locked for 5 min)","Send USDC onchain: call transfer() on usdc_contract, sending amount to payment.address on Base (chain ID 8453)","POST /purchase {\"game_id\":\"...\",\"tx_hash\":\"0x...\",\"quote_id\":\"...\"} — receive product key. If 410 → quote expired, use new quote_id from response."],"total_http_calls":3},"sandbox_testing":{"description":"Test the full purchase flow without spending real money. Uses Base Sepolia testnet.","steps":["Get Sepolia ETH from faucet (for gas): https://www.alchemy.com/faucets/base-sepolia","Get Sepolia USDC from Circle faucet: https://faucet.circle.com/","POST /purchase {\"game_id\":\"...\", \"chain\":\"base-sepolia\"} — receive 402 with Sepolia payment details","Send Sepolia USDC onchain to the address in the 402 response","POST /purchase {\"game_id\":\"...\", \"tx_hash\":\"0x...\", \"chain\":\"base-sepolia\"} — receive mock key (SANDBOX-XXXXX-...)"],"note":"Mock keys start with SANDBOX- and cannot be redeemed. All other behavior (verification, pricing, double-spend protection) is identical to production."},"agent_without_wallet":{"description":"Agent cannot send crypto. User handles payment, agent handles API calls.","steps":["GET /games/match?title=...&platform=... — find the best matching product","POST /purchase {\"game_id\":\"...\"} — receive 402 with payment details + quote_id (price locked for 5 min)","Present to user: payment_url (ERC-20 URI for wallet payment). Inform user they have 5 minutes for the quoted price.","User pays from their wallet and provides tx_hash back to agent (or agent monitors the wallet for incoming USDC)","POST /purchase {\"game_id\":\"...\",\"tx_hash\":\"0x...\",\"quote_id\":\"...\"} — receive product key. If 410 → quote expired, use new quote_id from response."],"total_http_calls":3,"user_steps":1,"note":"payment_url is an EIP-681 URI for direct wallet payment (instant)."}}}