{"openapi":"3.1.0","info":{"title":"x402-extract","version":"1.0.0","description":"Pay-per-call extraction for AI agents on Base via x402. No API keys, no accounts. POST /extract: URL in, clean markdown out. POST /extract-fields: text in, structured JSON out via deterministic regex (no LLM) — misses return null, never invented text.","x-guidance":{"/extract":"Use for extracting clean readable content from a public web page. Returns markdown/text. Fails honestly on unreadable URLs.","/extract-fields":"Use for deterministic field extraction. Returns null when not found — never invents. Every requested field is present in the response; missing values are listed by name.","/v1/balance/:address":"Use for checking a wallet's native ETH balance on Base. Returns wei and ETH as strings plus the block number — no API key, $0.003 per call.","/v1/block/latest":"Use for the latest Base block number, hash, and timestamp in one call — $0.002 per call.","/v1/changed":"Use for detecting what changed on a public page since you last saw it. Stateless: pass the text you last saw as `previous` (no stored baseline). Returns added/removed lines plus hashes — $0.008 per call."}},"servers":[{"url":"https://x402-extract-wg5z.onrender.com"}],"paths":{"/extract":{"post":{"summary":"Extract clean readable content from a public web page","description":"URL in, markdown/text out. A 200 with content:\"\" means the page loaded successfully and was genuinely empty. Unpaid requests return 402 with an x402 v2 payment challenge. Failures return 4xx/5xx with a machine-readable {error, reason} body and are never settled.","x-payment-info":{"protocols":["x402"],"price":{"mode":"fixed","currency":"USD","amount":"0.01"}},"security":[{"x402":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Public web page URL to extract"},"format":{"type":"string","enum":["markdown","text"],"default":"markdown"}}}}}},"responses":{"200":{"description":"Extracted content","content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"final_url":{"type":"string"},"content":{"type":"string"},"word_count":{"type":"integer"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"402":{"description":"Payment required. The response carries a PAYMENT-REQUIRED header with the x402 v2 challenge (accepts block). Sign the USDC payment and retry with the signed payload in PAYMENT-SIGNATURE.","headers":{"PAYMENT-REQUIRED":{"description":"Base64-encoded x402 v2 PaymentRequired payload","schema":{"type":"string"}}}},"4XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"5XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}}}}},"/extract-fields":{"post":{"summary":"Extract structured fields from text via deterministic regex","description":"Text in, JSON out. 15 supported fields (email, phone, url, date, amount, currency, invoice_no, order_id, name, company, address, zip, country, percentage, quantity). Every requested field is returned: found with a confidence score, or null and listed in missing. No LLM, no invented text. Unpaid requests return 402 with an x402 v2 payment challenge. A 200 with found:0 means the text was processable but no fields matched; unprocessable input returns 400 with a coded {error, reason} body. 4xx/5xx responses are never settled.","x-payment-info":{"protocols":["x402"],"price":{"mode":"fixed","currency":"USD","amount":"0.02"}},"security":[{"x402":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text","fields"],"properties":{"text":{"type":"string","minLength":10,"maxLength":10000,"description":"Text to extract fields from"},"fields":{"type":"array","minItems":1,"maxItems":15,"items":{"type":"string"},"description":"Subset of the 15 supported field names"}}}}}},"responses":{"200":{"description":"Extraction result","content":{"application/json":{"schema":{"type":"object","properties":{"extracted":{"type":"object","description":"Field name -> value, or null for misses"},"found":{"type":"integer"},"total":{"type":"integer"},"missing":{"type":"array","items":{"type":"string"}},"confidence":{"type":"object","description":"Field name -> 0..1 confidence score"}}}}}},"400":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"402":{"description":"Payment required. The response carries a PAYMENT-REQUIRED header with the x402 v2 challenge (accepts block). Sign the USDC payment and retry with the signed payload in PAYMENT-SIGNATURE.","headers":{"PAYMENT-REQUIRED":{"description":"Base64-encoded x402 v2 PaymentRequired payload","schema":{"type":"string"}}}},"5XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}}}}},"/validate":{"get":{"summary":"Free preview: first ~500 chars of the real extraction, no wallet","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["markdown","text"]}}],"responses":{"200":{"description":"Preview of the extraction result — title, word count, ~500-char content excerpt, plus a pointer to the paid full call"}}}},"/validate-fields":{"get":{"summary":"Free demo: real field extraction on your text, no wallet","parameters":[{"name":"fields","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated field names"},{"name":"text","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full extraction result, same shape as the paid call"}}}},"/health":{"get":{"summary":"Service status","responses":{"200":{"description":"Network, price, payTo, active facilitator"}}}},"/v1/balance/{address}":{"get":{"summary":"Native ETH balance for a wallet on Base","description":"Wallet address in, balance out. Returns wei (string), ETH (string), and the block number. Unpaid requests return 402. Failures return 4xx/5xx with a machine-readable {error, reason} body and are never settled.","x-payment-info":{"protocols":["x402"],"price":{"mode":"fixed","currency":"USD","amount":"0.003"}},"security":[{"x402":[]}],"parameters":[{"name":"address","in":"path","required":true,"schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"description":"Wallet address (0x + 40 hex chars)"}],"responses":{"200":{"description":"Balance","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string"},"balance_wei":{"type":"string"},"balance_eth":{"type":"string"},"block_number":{"type":"integer"},"chain":{"type":"string"}}}}}},"402":{"description":"Payment required. The response carries a PAYMENT-REQUIRED header with the x402 v2 challenge (accepts block). Sign the USDC payment and retry with the signed payload in PAYMENT-SIGNATURE.","headers":{"PAYMENT-REQUIRED":{"description":"Base64-encoded x402 v2 PaymentRequired payload","schema":{"type":"string"}}}},"4XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"5XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}}}}},"/v1/block/latest":{"get":{"summary":"Latest Base block number, hash, and timestamp","description":"One machine-readable call for chain height. Unpaid requests return 402. Failures return 4xx/5xx with a machine-readable {error, reason} body and are never settled.","x-payment-info":{"protocols":["x402"],"price":{"mode":"fixed","currency":"USD","amount":"0.002"}},"security":[{"x402":[]}],"responses":{"200":{"description":"Latest block","content":{"application/json":{"schema":{"type":"object","properties":{"block_number":{"type":"integer"},"block_hash":{"type":"string"},"timestamp":{"type":"integer"},"chain":{"type":"string"}}}}}},"402":{"description":"Payment required. The response carries a PAYMENT-REQUIRED header with the x402 v2 challenge (accepts block). Sign the USDC payment and retry with the signed payload in PAYMENT-SIGNATURE.","headers":{"PAYMENT-REQUIRED":{"description":"Base64-encoded x402 v2 PaymentRequired payload","schema":{"type":"string"}}}},"4XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"5XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}}}}},"/v1/changed":{"get":{"summary":"Deterministic line diff of a public page against text you supply","description":"Stateless by design: the server holds no baseline (free-tier memory resets), so you pass the text you last saw as `previous` (≤10,000 chars). Returns what was added/removed, line by line, plus SHA-256 hashes of both texts. Unpaid requests return 402. Failures return 4xx/5xx with a machine-readable {error, reason} body and are never settled.","x-payment-info":{"protocols":["x402"],"price":{"mode":"fixed","currency":"USD","amount":"0.008"}},"security":[{"x402":[]}],"parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"Public page URL"},{"name":"previous","in":"query","required":true,"schema":{"type":"string","maxLength":10000},"description":"Text you last saw"}],"responses":{"200":{"description":"Diff result","content":{"application/json":{"schema":{"type":"object","properties":{"changed":{"type":"boolean"},"current_hash":{"type":"string"},"previous_hash":{"type":"string"},"added_count":{"type":"integer"},"removed_count":{"type":"integer"},"added":{"type":"array","items":{"type":"string"}},"removed":{"type":"array","items":{"type":"string"}},"url":{"type":"string"}}}}}},"402":{"description":"Payment required. The response carries a PAYMENT-REQUIRED header with the x402 v2 challenge (accepts block). Sign the USDC payment and retry with the signed payload in PAYMENT-SIGNATURE.","headers":{"PAYMENT-REQUIRED":{"description":"Base64-encoded x402 v2 PaymentRequired payload","schema":{"type":"string"}}}},"4XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"5XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}}}}},"/validate-changed":{"get":{"summary":"Free preview for /v1/changed (content hash only)","description":"No payment. Returns the current SHA-256 content hash of a public page so you can decide whether the paid diff is worth it. Never substitutes the product.","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"Public page URL"}],"responses":{"200":{"description":"Content hash preview","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"final_url":{"type":"string"},"title":{"type":"string"},"content_hash":{"type":"string"},"content_length":{"type":"integer"},"preview":{"type":"boolean"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"4XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}},"5XX":{"description":"Structured failure. 4xx/5xx responses cancel the x402 settlement before it executes — you are only charged when the handler returns 200.","content":{"application/json":{"schema":{"type":"object","required":["error","reason","message","fetched_at"],"properties":{"error":{"type":"string","description":"Coarse stable error code"},"reason":{"type":"string","description":"Machine-readable discriminator; switch on this, not message text"},"message":{"type":"string","description":"Human-readable detail"},"url":{"type":"string","description":"URL that was attempted (/extract only)"},"upstream_status":{"type":"integer","description":"Origin HTTP status when reason is origin_4xx/origin_5xx"},"fetched_at":{"type":"string","format":"date-time"}}}}}}}}}},"components":{"securitySchemes":{"x402":{"type":"apiKey","in":"header","name":"PAYMENT-SIGNATURE","description":"x402 v2 payment. Make the unpaid request, take the 402 challenge, sign the USDC payment with your wallet, retry with the signed payload in PAYMENT-SIGNATURE."}}}}