# Dial x402 — Complete API Reference > Virtual phone numbers for AI agents and privacy. Monthly prepaid via x402 crypto payments on Base. Dashboard via Privy. Base URL: https://x402.dial.wtf Facilitator: https://facilitator.openx402.ai MCP: https://x402.dial.wtf/mcp Discovery: https://x402.dial.wtf/discovery/resources Protocol: https://x402.dial.wtf/.well-known/x402 --- ## AUTH: x402 Payment Protocol All paid endpoints return HTTP 402 when called without payment. ### How it works: 1. POST to endpoint without payment → receive 402 2. Read Payment-Required header (base64-encoded JSON): { "x402Version": 2, "accepts": [{ "scheme": "exact", "network": "eip155:8453", "amount": "20000000", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "payTo": "0x..." }] } 3. amount is in USDC atomic units (6 decimals). "20000000" = $20.00 4. Sign EIP-3009 transferWithAuthorization for the amount to the payTo address 5. Base64-encode the signed authorization 6. Resubmit original request with header: Payment-Signature: 7. Server verifies via facilitator, settles on-chain, returns 200 ### JavaScript setup: ```javascript import { privateKeyToAccount } from "viem/accounts"; import { createWalletClient, http } from "viem"; import { base } from "viem/chains"; import { wrapFetchWithPayment } from "@x402/fetch"; import { x402Client } from "@x402/core/client"; import { ExactEvmScheme } from "@x402/evm/exact/client"; import { toClientEvmSigner } from "@x402/evm"; const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY"); const walletClient = createWalletClient({ account, chain: base, transport: http(), }); const signer = toClientEvmSigner(walletClient); const client = new x402Client(); client.register("eip155:*", new ExactEvmScheme(signer)); const paidFetch = wrapFetchWithPayment(fetch, client); // Buy a US phone line ($100 activation) const res = await paidFetch("https://x402.dial.wtf/api/v1/numbers/buy/us", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ country: "US" }), }); ``` ### Networks: - Base mainnet: eip155:8453 — USDC: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 - Base Sepolia: eip155:84532 — USDC: 0x036CbD53842c5426634e7929541eC2318f3dCF7e --- ## AUTH: SIWE (Sign-In with Ethereum) After purchasing a virtual number via x402, manage it using SIWE. The wallet that paid for the number can authenticate and view/manage their numbers. ### Step 1: Get a nonce GET /api/v1/auth/siwe?address=0xYOUR_ADDRESS&chainId=8453 Response: { "nonce": "a1b2c3d4e5f6...", "message": "x402.dial.wtf wants you to sign in with your Ethereum account:\n0xYOUR_ADDRESS\n\nSign in to manage your Dial virtual phone numbers.\n\nURI: https://x402.dial.wtf\nVersion: 1\nChain ID: 8453\nNonce: a1b2c3d4e5f6...\nIssued At: 2026-03-26T...\nExpiration Time: 2026-03-27T..." } ### Step 2: Sign and verify POST /api/v1/auth/siwe Request: { "message": "", "signature": "0x" } Response: { "success": true, "token": "", "address": "0xYOUR_ADDRESS", "expiresAt": "2026-03-27T..." } ### Step 3: Use session token GET /api/v1/numbers/mine Authorization: Bearer --- ## ENDPOINT: Buy Phone Line (US) ### POST /api/v1/numbers/buy/us Price: $100.00 USDC | Auth: x402 Buy an exclusive US phone line. $100 activation includes first month + 10,000 free texts. Renews at $60/mo with 5,000 free texts. The paying wallet can manage it via SIWE. Request: { "country": "US" // Required. "US" only } Response (200): { "success": true, "provider": "dial", "phoneNumber": "+12125551234", "country": "US", "orderId": "uuid-xxx", "priceUsd": 100, "included": { "texts": 10000, "periodDays": 30 }, "renewal": { "priceUsd": 60, "texts": 5000, "periodDays": 30 }, "expiresAt": "2026-04-26T00:00:00.000Z", "managementInfo": "Manage your number at /api/v1/numbers/mine. Authenticate with SIWE." } --- ## ENDPOINT: Buy Phone Line (International) ### POST /api/v1/numbers/buy/intl Price: $100.00 USDC | Auth: x402 Buy an exclusive international phone line. $100 activation includes first month + 10,000 free texts. Renews at $60/mo with 5,000 free texts. Excludes US (use /buy/us endpoint). Request: { "country": "GB" // ISO country code. Excludes US (use /buy/us endpoint) } Response (200): { "success": true, "provider": "dial", "phoneNumber": "+447700900123", "country": "GB", "orderId": "uuid-xxx", "priceUsd": 100, "included": { "texts": 10000, "periodDays": 30 }, "renewal": { "priceUsd": 60, "texts": 5000, "periodDays": 30 }, "expiresAt": "2026-04-26T00:00:00.000Z", "managementInfo": "Manage your number at /api/v1/numbers/mine. Authenticate with SIWE." } --- ## ENDPOINT: Send SMS (A La Carte) ### POST /api/v1/sms/send Price: $0.05 USDC | Auth: x402 Send a one-off SMS from a Dial pool number. No phone number purchase required. Max message length: 900 characters. Request: { "to": "+1234567890", // Required. Recipient phone (E.164) "message": "Hello!" // Required. Max 900 chars } Response (200): { "success": true, "messageId": "msg-uuid", "to": "+1234567890", "segments": 1 } --- ## ENDPOINT: Send SMS (Own Line) ### POST /api/v1/numbers/mine/send Price: $0.05 USDC | Auth: x402 + SIWE Bearer Send SMS from your own provisioned virtual number. Requires both: 1. x402 payment ($0.05 per message) 2. SIWE session token (proving you own the number) Headers: Authorization: Bearer Payment: Request: { "phoneNumber": "+12125551234", // Required. Your provisioned number "to": "+0987654321", // Required. Recipient phone (E.164) "message": "Hello from my number" // Required. Max 900 chars } Response (200): { "success": true, "messageId": "msg-uuid", "to": "+0987654321", "segments": 1 } --- ## ENDPOINT: My Numbers (SIWE-protected) ### GET /api/v1/numbers/mine Auth: Bearer (SIWE session token) Returns all virtual numbers owned by the authenticated wallet. Add ?all=true to include expired numbers. Response (200): { "success": true, "address": "0xYOUR_ADDRESS", "numbers": [ { "phoneNumber": "+12125551234", "country": "US", "tier": "us", "priceUsd": 100.00, "leasedAt": "2026-03-26T...", "expiresAt": "2026-04-26T...", "status": "active" } ], "count": 1 } --- ## ENDPOINT: Service Discovery ### GET /api/v1/discovery Auth: free Returns OpenX402-compatible resource metadata (prices, networks, payTo addresses). ### GET /discovery/resources Bazaar-standard resource catalog. Pagination: ?offset=0&limit=100&type=http ### GET /.well-known/x402 Protocol metadata: version, networks, facilitators, payTo address. --- ## COMING SOON ### POST /api/v1/lookup — $0.05 Reverse phone lookup — line type, carrier, caller name, SIM swap, line status. ### POST /api/v1/dehashed/search — $0.05 Search breach/leak databases by email, phone, IP, domain, username, password hash. ### POST /api/v1/credits/top-up — $5.00 Buy 100 prepaid credits at $0.05/credit (also requires Bearer token). ### POST /api/v1/verifications/start — $2.25 Start a phone verification (OTP). ### POST /api/v1/esim/checkout — $2.45 Purchase an eSIM data plan for 180+ countries. --- ## MCP SERVER Endpoint: https://x402.dial.wtf/mcp Protocol: Model Context Protocol (JSON-RPC over HTTP) Transport: Streamable HTTP (GET for SSE, POST for messages) Available tools: - buy_number ($100.00) — Buy an exclusive phone line — 10k texts included ($100, then $60/mo) - buy_number_us ($100.00) — Buy an exclusive US phone line ($100, then $60/mo) - buy_number_intl ($100.00) — Buy an exclusive international phone line ($100, then $60/mo) - send_sms ($0.05) — Send a one-off SMS to any phone worldwide ($0.05) - discovery (free) — List all endpoints and pricing ### JavaScript MCP client: ```javascript import { experimental_createMCPClient as createMCPClient } from "ai"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { withPayment } from "x402-mcp"; const mcpClient = await createMCPClient({ transport: new StreamableHTTPClientTransport("https://x402.dial.wtf/mcp"), }); const client = await withPayment(mcpClient, { account: purchaserAccount, network: "base", }); const tools = await client.tools(); // buy_number_us ($100), buy_number_intl ($100), send_sms ($0.05), discovery (free) ``` --- ## ERROR CODES | Code | Meaning | |------|---------| | 200 | Success | | 400 | Bad request — validation error in request body | | 402 | Payment required or payment verification failed | | 401 | Unauthorized — invalid or missing SIWE session | | 429 | Rate limited — 60 requests/minute. Check Retry-After header | | 502 | Upstream provider error | | 500 | Internal server error | All error responses: { "error": "error_code", "message": "Human-readable description" } Rate limit headers on every response: - X-RateLimit-Remaining: requests left in window - X-Request-Id: unique request ID for debugging --- ## CORS All endpoints allow cross-origin requests: - Access-Control-Allow-Origin: * - Access-Control-Allow-Headers: Authorization, Content-Type, Payment-Signature, Payment-Response - Access-Control-Expose-Headers: Payment-Required, Payment-Response, X-Request-Id --- ## LINKS - Docs: https://x402.dial.wtf/docs - Getting Started: https://x402.dial.wtf/docs/getting-started - API Reference: https://x402.dial.wtf/docs/api-reference - GitHub: https://github.com/Dial-WTF/ - OpenX402: https://openx402.ai - x402 Protocol: https://docs.x402.org