{"openapi":"3.1.0","info":{"title":"x402station — Pre-flight Oracle","version":"1.0.0","description":"Agent-to-agent oracle for the x402 network. Call us before any paid x402 request to detect decoys, zombie endpoints, and price traps.","contact":{"name":"x402station","email":"hello@x402station.io","url":"https://github.com/sF1nX/x402station-mcp"},"license":{"name":"MIT","url":"https://github.com/sF1nX/x402station-mcp/blob/main/LICENSE"}},"servers":[{"url":"https://x402station.io"}],"x-x402":{"version":2,"facilitator":"https://x402.org/facilitator","networks":["eip155:8453","eip155:84532"],"asset":"USDC","scheme":"exact","payTo":"0x4053338C7cB38624C0bc23c900F78Cf8470b4E38"},"paths":{"/api/v1/preflight":{"post":{"summary":"Pre-flight check for any x402 endpoint URL","description":"Returns {ok, warnings, metadata} telling the agent if the target URL is safe to pay. Gated by x402 at $0.001 USDC — the first call returns 402 with payment requirements, retry with X-PAYMENT header.","x-x402-price":"$0.001","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Full URL of the x402 endpoint the agent is about to pay","example":"https://api.venice.ai/api/v1/chat/completions"}}}}}},"responses":{"200":{"description":"Pre-flight report (after successful payment)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"true only when no critical warning"},"warnings":{"type":"array","items":{"type":"string","enum":["unknown_endpoint","no_history","dead","zombie","decoy_price_extreme","suspicious_high_price","slow","new_provider"]}},"metadata":{"type":"object","properties":{"url":{"type":"string"},"service":{"type":"string"},"service_id":{"type":"string"},"price_usdc":{"type":"string"},"currency":{"type":"string"},"uptime_1h_pct":{"type":["integer","null"]},"avg_latency_ms":{"type":["integer","null"]},"is_active":{"type":"boolean"}}}}}}}},"400":{"description":"Malformed body — `url` required and must start with http(s)"},"402":{"description":"Payment required — sign X-PAYMENT per x402 v2 and retry","headers":{"payment-required":{"description":"Base64-encoded x402 v2 PaymentRequiredResponse. Parse and sign with your wallet.","schema":{"type":"string"}}}},"503":{"description":"DB query exceeded its statement_timeout (preflight 5s / forensics 10s / decoys 15s). Payment is already settled — agent should NOT retry the same request quickly (next probe data may be 5-10 min away). Returns { error, detail }.","content":{"application/json":{}}}}}},"/api/v1/forensics":{"post":{"summary":"Deep 7-day forensics report for an x402 endpoint","description":"Superset of preflight. Returns hourly uptime series, latency p50/p90/p99, status-code distribution, concentration-group stats (how crowded this provider's namespace is), and a decoy probability score [0, 1]. Priced $0.001 USDC — same as preflight (currently the CDP facilitator floor); forensics returns ~50× more data per call. Agents pulling forensics can skip a separate preflight call.","x-x402-price":"$0.001","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Full URL of the x402 endpoint to analyse","example":"https://api.venice.ai/api/v1/chat/completions"}}}}}},"responses":{"200":{"description":"Forensics report (after successful payment)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"string","enum":["unknown_endpoint","no_history","dead","zombie","decoy_price_extreme","suspicious_high_price","slow","new_provider","dead_7d","mostly_dead","slow_p99","price_outlier_high","high_concentration"]}},"decoy_probability":{"type":"number","minimum":0,"maximum":1,"description":"Blended risk score. 0 = clean, 1 = almost certainly a decoy."},"metadata":{"type":"object"},"uptime":{"type":"object","properties":{"probes_7d":{"type":"integer"},"healthy_7d":{"type":"integer"},"errors_7d":{"type":"integer"},"uptime_7d_pct":{"type":["integer","null"]},"uptime_1h_pct":{"type":["integer","null"]},"avg_latency_1h_ms":{"type":["integer","null"]},"hourly":{"type":"array","description":"Hourly buckets over the last 7 days, most recent first.","items":{"type":"object","properties":{"bucket":{"type":"string","format":"date-time"},"probes":{"type":"integer"},"healthy":{"type":"integer"},"avg_latency_ms":{"type":["integer","null"]}}}}}},"latency":{"type":"object","properties":{"p50_ms":{"type":["integer","null"]},"p90_ms":{"type":["integer","null"]},"p99_ms":{"type":["integer","null"]},"max_ms":{"type":["integer","null"]}}},"status_codes":{"type":"object","description":"Map of HTTP status code (or 'network_error') → count over the 7-day window.","additionalProperties":{"type":"integer"}},"concentration":{"type":"object","properties":{"group_size":{"type":"integer","description":"Endpoints in the catalog that share this endpoint's provider/domain."},"catalog_total":{"type":"integer"},"concentration_pct":{"type":["number","null"],"description":"group_size / catalog_total × 100, rounded to 1 decimal."},"group_median_price_usdc":{"type":["number","null"]},"group_p90_price_usdc":{"type":["number","null"]},"price_ratio_to_median":{"type":["number","null"],"description":"Current price / group median. ≥10 → price_outlier_high."}}}}}}}},"400":{"description":"Malformed body — `url` required and must start with http(s)"},"402":{"description":"Payment required — sign X-PAYMENT per x402 v2 and retry","headers":{"payment-required":{"description":"Base64-encoded x402 v2 PaymentRequiredResponse. Parse and sign with your wallet.","schema":{"type":"string"}}}},"503":{"description":"DB query exceeded its statement_timeout (preflight 5s / forensics 10s / decoys 15s). Payment is already settled — agent should NOT retry the same request quickly (next probe data may be 5-10 min away). Returns { error, detail }.","content":{"application/json":{}}}}}},"/api/v1/catalog/decoys":{"post":{"summary":"Full list of x402 endpoints flagged as dangerous","description":"Returns every active endpoint the oracle currently flags with a critical signal (decoy_price_extreme, zombie, dead_7d, mostly_dead), plus per-reason counts. Intended for agents to pull periodically and cache locally as a blacklist — cheaper than preflight-ing every URL. Priced $0.005 USDC.","x-x402-price":"$0.005","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"description":"No parameters. POST with {} or no body."}}}},"responses":{"200":{"description":"Known-bad list (after successful payment)","content":{"application/json":{"schema":{"type":"object","properties":{"generated_at":{"type":"string","format":"date-time"},"counts":{"type":"object","properties":{"total":{"type":"integer"},"by_reason":{"type":"object","additionalProperties":{"type":"integer"}}}},"truncated":{"type":"boolean","description":"True if result hit the MAX_ENTRIES cap and was cut off."},"entries":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"service_id":{"type":"string"},"service_name":{"type":"string"},"provider":{"type":["string","null"]},"price_usdc":{"type":["string","null"]},"currency":{"type":["string","null"]},"reasons":{"type":"array","items":{"type":"string","enum":["decoy_price_extreme","zombie","dead_7d","mostly_dead"]}},"probes_7d":{"type":"integer"},"healthy_7d":{"type":"integer"},"uptime_7d_pct":{"type":["integer","null"]},"last_probe_at":{"type":["string","null"],"format":"date-time"}}}}}}}}},"402":{"description":"Payment required — sign X-PAYMENT per x402 v2 and retry","headers":{"payment-required":{"description":"Base64-encoded x402 v2 PaymentRequiredResponse. Parse and sign with your wallet.","schema":{"type":"string"}}}},"503":{"description":"DB query exceeded its statement_timeout (preflight 5s / forensics 10s / decoys 15s). Payment is already settled — agent should NOT retry the same request quickly (next probe data may be 5-10 min away). Returns { error, detail }.","content":{"application/json":{}}}}}},"/api/v1/alternatives":{"post":{"summary":"Routing fallback — siblings to a flagged x402 endpoint","description":"Given a URL flagged by preflight (or a `taskClass` hint), returns up to 5 healthy sibling endpoints in the same provider/domain/category/price-band. Filters out 7-day-dead and 1-hour-erroring candidates; ranks by uptime_7d_pct DESC, avg_latency_1h_ms ASC. Solves the routing-fallback question that follows ok=false from preflight: where do I go instead? Priced $0.005 USDC.","x-x402-price":"$0.005","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","example":"https://api.venice.ai/api/v1/chat/completions","description":"URL to find alternatives for. The oracle looks up the target's service / provider / domain / category / price band and matches siblings against any one of those keys."},"taskClass":{"type":"string","maxLength":80,"description":"Service category hint (e.g. \"llm-completions\"). Used as a fallback match key when `url` is unknown to the catalog, OR by itself when the agent only has a task class in mind."},"limit":{"type":"integer","minimum":1,"maximum":10,"default":5}},"description":"At least one of `url` or `taskClass` is required."}}}},"responses":{"200":{"description":"Alternatives list (after successful payment)","content":{"application/json":{"schema":{"type":"object","properties":{"target":{"type":"object","description":"Target endpoint metadata when `url` resolved to a known catalog row. When the URL is unknown, returns `{ url, known: false }`. When only `taskClass` was supplied, returns `{ task_class }`."},"match_strategy":{"type":"string","enum":["url_target","task_class_only","url_target_unknown_fallback"]},"alternatives":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"service":{"type":"string"},"service_id":{"type":"string"},"provider":{"type":["string","null"]},"domain":{"type":["string","null"]},"category":{"type":["string","null"]},"price_usdc":{"type":["string","null"]},"currency":{"type":["string","null"]},"uptime_1h_pct":{"type":["number","null"]},"uptime_7d_pct":{"type":["number","null"]},"avg_latency_1h_ms":{"type":["integer","null"]},"match_reason":{"type":"string","enum":["same_service","same_provider","same_domain","same_category","similar_price"]}}}},"candidate_count":{"type":"integer","description":"Total eligible candidates BEFORE the LIMIT was applied. Lets agents detect 'we returned 5 but there were 200 more'."}}}}}},"400":{"description":"Malformed body — at least one of `url` (http(s), <=2048 chars) or `taskClass` (<=80 chars) required; `limit` must be an integer in [1, 10]."},"402":{"description":"Payment required — sign X-PAYMENT per x402 v2 and retry","headers":{"payment-required":{"description":"Base64-encoded x402 v2 PaymentRequiredResponse. Parse and sign with your wallet.","schema":{"type":"string"}}}},"503":{"description":"DB query exceeded its statement_timeout (alternatives 8s). Payment is already settled — agent should NOT retry the same request quickly. Returns { error, detail }.","content":{"application/json":{}}}}}},"/api/v1/whats-new":{"post":{"summary":"Catalog diff polling — what was added / removed since `since`","description":"Polling-friendly catalog diff. Returns added_endpoints[] (`first_seen_at >= since` AND `is_active = true`), removed_endpoints[] (flipped to `is_active = false` since), plus service-level counts, polls_in_window, and current active totals. Default window is 24h; cap is 30 days back. Priced $0.001 USDC — hourly polling costs ~$0.024/day. Internal ingest cron runs every 5 min, so polling more often than that returns identical data.","x-x402-price":"$0.001","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"since":{"type":"string","format":"date-time","description":"ISO 8601 timestamp. Default = now - 24h. Cannot be older than 30 days or in the future."},"limit":{"type":"integer","minimum":1,"maximum":500,"default":200,"description":"Per-list cap. Applied independently to added_endpoints and removed_endpoints. `truncated` flag indicates the cap was hit AND more rows existed."}}}}}},"responses":{"200":{"description":"Catalog diff (after successful payment)","content":{"application/json":{"schema":{"type":"object","properties":{"since":{"type":"string","format":"date-time"},"until":{"type":"string","format":"date-time"},"window_hours":{"type":"number"},"added_endpoints":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"service_id":{"type":"string"},"service_name":{"type":"string"},"provider":{"type":["string","null"]},"domain":{"type":["string","null"]},"category":{"type":["string","null"]},"price_usdc":{"type":["string","null"]},"currency":{"type":["string","null"]},"first_seen_at":{"type":"string","format":"date-time"}}}},"removed_endpoints":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"service_id":{"type":"string"},"service_name":{"type":"string"},"provider":{"type":["string","null"]},"domain":{"type":["string","null"]},"category":{"type":["string","null"]},"price_usdc":{"type":["string","null"]},"currency":{"type":["string","null"]},"last_seen_at":{"type":"string","format":"date-time"}}}},"summary":{"type":"object","properties":{"added_endpoints_count":{"type":"integer"},"removed_endpoints_count":{"type":"integer"},"added_services_count":{"type":"integer"},"removed_services_count":{"type":"integer"},"polls_in_window":{"type":"integer"},"first_poll_at":{"type":["string","null"],"format":"date-time"},"last_poll_at":{"type":["string","null"],"format":"date-time"},"current_active_endpoints":{"type":"integer"},"current_active_services":{"type":"integer"}}},"truncated":{"type":"boolean"},"limit":{"type":"integer"}}}}}},"400":{"description":"Malformed body — `since` not a valid ISO timestamp / older than 30 days / in the future; `limit` not an integer in [1, 500]."},"402":{"description":"Payment required — sign X-PAYMENT per x402 v2 and retry","headers":{"payment-required":{"description":"Base64-encoded x402 v2 PaymentRequiredResponse. Parse and sign with your wallet.","schema":{"type":"string"}}}},"503":{"description":"DB query failed (statement_timeout=5s). Payment is already settled — agent should not retry quickly. Returns { error, detail }.","content":{"application/json":{}}}}}},"/api/v1/watch":{"post":{"summary":"Subscribe to webhook alerts on x402 endpoint state changes","description":"Pay $0.01 USDC for a 30-day subscription with 100 prepaid alerts. When subscribed signals fire/clear (e.g. dead, zombie, decoy_price_extreme), x402station POSTs an HMAC-SHA256-signed JSON payload to your webhookUrl. The secret returned here is the HMAC seed — store it; not retrievable later. Quota note: when alerts_sent reaches alerts_paid, future state changes still update internal state but no webhook is delivered (skipped_quota_exceeded; visible via GET).","x-x402-price":"$0.01","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","webhookUrl"],"properties":{"url":{"type":"string","format":"uri","description":"The x402 endpoint URL to watch."},"webhookUrl":{"type":"string","format":"uri","description":"Where x402station will POST alert payloads. Must be reachable from the public internet."},"signals":{"type":"array","items":{"type":"string","enum":["unknown_endpoint","no_history","dead","zombie","decoy_price_extreme","suspicious_high_price","slow","new_provider","dead_7d","mostly_dead","slow_p99","price_outlier_high","high_concentration"]},"minItems":1,"maxItems":20,"description":"Optional. Defaults to ['dead', 'zombie', 'decoy_price_extreme']. Whitelisted to known signal vocabulary so a typo doesn't silently never fire."}}}}}},"responses":{"200":{"description":"Subscription created (after successful payment)","content":{"application/json":{"schema":{"type":"object","properties":{"watchId":{"type":"string","format":"uuid"},"secret":{"type":"string","description":"64-char hex HMAC seed. Returned ONCE here. Store it."},"expiresAt":{"type":"string","format":"date-time"},"signals":{"type":"array","items":{"type":"string"}},"alertsPaid":{"type":"integer"},"alertsRemaining":{"type":"integer"},"endpointKnown":{"type":"boolean","description":"true if the watched URL is in our catalog. false ⇒ alerts will fire only after ingest picks the URL up."},"deliveryFormat":{"type":"object","description":"Documents how to verify HMAC signatures + the JSON shape of alert payloads."}},"required":["watchId","secret","expiresAt","signals","alertsPaid"]}}}},"400":{"description":"Bad input (malformed URL, unknown signal, etc.)"},"402":{"description":"Payment required — sign X-PAYMENT per x402 v2 and retry","headers":{"payment-required":{"description":"Base64-encoded x402 v2 PaymentRequiredResponse. Parse and sign with your wallet.","schema":{"type":"string"}}}},"503":{"description":"DB write timed out (statement_timeout=5s). Payment is already settled — same constraint as preflight/forensics/decoys.","content":{"application/json":{}}}}}},"/api/v1/watch/{watchId}":{"get":{"summary":"Watch subscription status + recent alert history","description":"Returns the current state of a watch (active/expired, alerts remaining, last_state snapshot, last 10 alert deliveries). Free, secret-gated. Pass the secret in header `x-x402station-secret` (preferred) or as `?secret=...` query string. Mismatched secret returns 404 (not 401) so an attacker scraping IDs can't distinguish 'exists with wrong secret' from 'doesn't exist'.","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-x402station-secret","in":"header","required":false,"schema":{"type":"string","minLength":64,"maxLength":64},"description":"64-char hex secret. Either this header or ?secret=… must be set."},{"name":"secret","in":"query","required":false,"schema":{"type":"string","minLength":64,"maxLength":64}}],"responses":{"200":{"description":"Watch state + recent alerts","content":{"application/json":{"schema":{"type":"object","properties":{"watchId":{"type":"string","format":"uuid"},"endpointUrl":{"type":"string"},"webhookUrl":{"type":"string"},"signals":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"alertsPaid":{"type":"integer"},"alertsSent":{"type":"integer"},"alertsRemaining":{"type":"integer"},"lastState":{"type":["object","null"]},"isActive":{"type":"boolean"},"expired":{"type":"boolean"},"recentAlerts":{"type":"array"}}}}}},"400":{"description":"Malformed watchId UUID"},"401":{"description":"Secret missing"},"404":{"description":"Watch not found OR secret mismatched (intentionally indistinguishable)"}}},"delete":{"summary":"Unsubscribe (deactivate) a watch","description":"Sets is_active=false. No further alerts are queued or delivered. Free, secret-gated (same auth as GET). Watch row + alert history are retained for audit. There is no refund for unused prepaid alerts.","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-x402station-secret","in":"header","required":false,"schema":{"type":"string","minLength":64,"maxLength":64}},{"name":"secret","in":"query","required":false,"schema":{"type":"string","minLength":64,"maxLength":64}}],"responses":{"200":{"description":"Unsubscribed (or already-unsubscribed)","content":{"application/json":{"schema":{"type":"object","properties":{"watchId":{"type":"string","format":"uuid"},"isActive":{"type":"boolean","const":false},"message":{"type":"string"}}}}}},"400":{"description":"Malformed watchId UUID"},"401":{"description":"Secret missing"},"404":{"description":"Watch not found OR secret mismatched (intentionally indistinguishable)"}}}},"/.well-known/x402":{"get":{"summary":"Service manifest (agent-readable)","description":"Describes all paid endpoints, pricing, and signals in one JSON document.","responses":{"200":{"description":"Manifest JSON","content":{"application/json":{}}}}}},"/llms.txt":{"get":{"summary":"AI-crawler-readable description (markdown by llms.txt convention)","responses":{"200":{"description":"Markdown body — emitted as text/markdown so Cloudflare's isitagentready scanner accepts it via Accept: text/markdown content negotiation.","content":{"text/markdown":{}}}}}}}}