{
  "x402Version": 2,
  "service": {
    "name": "2s",
    "description": "Unified JSON REST API for AI agents. Pay per call in USDC on Base via x402. No accounts, no API keys.",
    "url": "https://2s.io",
    "homepage": "https://2s.io",
    "directory": "https://2s.io/api/directory",
    "openapi": "https://2s.io/api/openapi",
    "llmsTxt": "https://2s.io/llms.txt",
    "mcpServerCard": "https://2s.io/.well-known/mcp/server-card.json"
  },
  "settlement": {
    "network": "eip155:8453",
    "asset": "USDC",
    "assetAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "assetName": "USD Coin",
    "assetVersion": "2",
    "treasury": "0x2b6D4988Db4723E6908Db86Ab2b8dFBc51FC32C5",
    "facilitator": "https://api.cdp.coinbase.com/platform/v2/x402",
    "facilitatorSpec": "https://x402.org"
  },
  "endpoints": [
    {
      "id": "ai.describe-image",
      "method": "POST",
      "path": "/api/ai/describe-image",
      "description": "Describe an image. POST { imageUrl, instruction? }. Returns { imageUrl, altText (5-15 word accessibility text), description (2-3 sentences), contentType (photograph|illustration|screenshot|diagram|document|mixed|other), text (verbatim OCR transcription, \"\" if none), mainObjects[], dominantColors[] (hex) }. Accepts JPEG, PNG, GIF, WebP. 1MB image size cap.",
      "priceUsd": 0.018
    },
    {
      "id": "ai.extract",
      "method": "POST",
      "path": "/api/ai/extract",
      "description": "Extract structured data from a webpage. POST { url, schema, instruction? }. The schema is a JSON Schema object (top-level type:\"object\") describing the shape you want back; output is guaranteed to conform. Returns { url, finalUrl, extracted, meta:{ truncated } }.",
      "priceUsd": 0.03
    },
    {
      "id": "ai.screenshot",
      "method": "POST",
      "path": "/api/ai/screenshot",
      "description": "Render a URL as a screenshot. POST { url, width?, height?, fullPage?, format?, quality?, waitUntil?, timeoutMs?, deviceScaleFactor?, blockAds? }. Returns raw image bytes (no JSON envelope) with X-2s-Render-Ms and X-2s-Image-Bytes headers. Viewport clamped 320-3840 × 320-2160. Timeout clamped 1-15s. Defaults: 1280×720 PNG, networkidle2 wait, ad-blocking on. Use cases: visual verification, archival, change detection, OG-card generation, RSS thumbnails.",
      "priceUsd": 0.0075
    },
    {
      "id": "ai.summarize",
      "method": "POST",
      "path": "/api/ai/summarize",
      "description": "Summarize a webpage. POST { url, instruction? }. Returns { url, finalUrl, summary (1-3 sentences), keyPoints (3-7 bullets), title, audience, estimatedReadingMinutes, meta:{ truncated } }. Sibling to /api/ai/extract — use extract when you need a typed payload conforming to your own schema; use summarize when you want a ready-made digest.",
      "priceUsd": 0.0225
    },
    {
      "id": "ai.translate",
      "method": "POST",
      "path": "/api/ai/translate",
      "description": "Translate text. POST { text, targetLanguage, sourceLanguage? } — language codes are BCP-47 (e.g. \"en\", \"es-MX\", \"zh-Hans\"). Source auto-detected when omitted. Returns { text, targetLanguage, detectedSourceLanguage, confidence (high|medium|low) }. Best for short-to-medium passages; chunk long documents on your side.",
      "priceUsd": 0.0075
    },
    {
      "id": "airport.lookup",
      "method": "GET",
      "path": "/api/airport/lookup",
      "description": "Look up an airport by 3-letter IATA (e.g. SFO) or 4-letter ICAO (e.g. KSFO) code. Query: code (3-5 chars, alphanumeric). Returns { airport: { id, ident, type, name, latitude, longitude, elevationFt, continent, isoCountry, isoRegion, municipality, scheduledService, icaoCode, iataCode, gpsCode, localCode, wikipediaLink } } or 404 NOT_FOUND.",
      "priceUsd": 0.001
    },
    {
      "id": "airport.near",
      "method": "GET",
      "path": "/api/airport/near",
      "description": "Airports within a radius of a coordinate, sorted by distance. Query: lat (-90..90), lon (-180..180), radius_km (1-2000, default 200), limit (1-100, default 20), type (optional: large_airport|medium_airport|small_airport|heliport|seaplane_base|balloonport|closed), country (optional 2-letter ISO 3166-1), scheduled_service (optional bool, true = commercial-service airports only). Returns { query, count, airports: [{ id, ident, name, iataCode, icaoCode, type, latitude, longitude, distanceKm, ... }] }.",
      "priceUsd": 0.001
    },
    {
      "id": "barcode.generate",
      "method": "POST",
      "path": "/api/barcode/generate",
      "description": "Generate QR / Aztec / Data Matrix / PDF417 codes from structured payloads (url, wifi, vcard, vevent, email, sms, tel, geo, bitcoin, json, text). QR supports rounded or dotted modules, solid colors or linear/radial gradients, transparent backgrounds, configurable error correction, and a centered logo image (URL or data URI).",
      "priceUsd": 0.001
    },
    {
      "id": "census.zipcode",
      "method": "GET",
      "path": "/api/census/zipcode",
      "description": "US Census ACS 5-year demographics for a ZIP code (ZCTA). Returns population, median age, median household income, poverty rate, household composition, race + ethnicity breakdown, education attainment, workforce (with computed unemployment rate), and housing (with computed owner-occupancy rate and median rent/home value). Backed by ~33k ZCTAs pre-ingested from api.census.gov; refreshed annually. Public-domain US government data.",
      "priceUsd": 0.001
    },
    {
      "id": "climate.station-near",
      "method": "GET",
      "path": "/api/climate/station-near",
      "description": "Find NOAA GHCN-Daily weather stations near a coordinate. Returns up to 100 stations within a configurable radius (default 500 km), sorted by distance. Each station includes id, name, lat/lon, elevation, country/state, and GSN/HCN/WMO flags. Backed by a ~132k-station registry refreshed monthly from ncei.noaa.gov.",
      "priceUsd": 0.001
    },
    {
      "id": "countdown.gif",
      "method": "GET",
      "path": "/api/countdown/gif",
      "description": "Animated countdown GIF from the current UTC time to endDate. Always uncached. Supports 5 templates (default, minimal, neon, retro, corporate) and full customization: colors, fonts, dimensions, padding, cell padding, labels, dividers. Animates for `seconds` frames at `fps`.",
      "priceUsd": 0.006
    },
    {
      "id": "crypto.address-validate",
      "method": "GET",
      "path": "/api/crypto/address-validate",
      "description": "Validate a cryptocurrency address with full checksum verification (not just regex). Returns {chain, address, valid, canonical, format, reason}. Chains: btc (P2PKH, P2SH, Bech32 SegWit v0, Taproot Bech32m), eth (full EIP-55 checksum; non-checksummed flagged), sol (Ed25519 32-byte Base58), ltc (Base58Check L.../M.../3... + ltc1 Bech32), trx (T-prefix Base58Check 0x41), xrp (r-prefix custom Base58), bch (legacy Base58Check + bitcoincash:q... CashAddr). Catches typos via cryptographic checksum; canonical field returns the checksummed/lowercased form.",
      "priceUsd": 0.001
    },
    {
      "id": "crypto.gas-oracle",
      "method": "GET",
      "path": "/api/crypto/gas-oracle",
      "description": "Live EVM gas oracle. Returns latest block baseFeePerGas + slow/standard/fast tiers derived from priority-fee percentiles (p25/p50/p75) over the trailing 4 blocks, plus a 21,000-gas transfer cost estimate in the chain native unit. Chains: base, ethereum, polygon, arbitrum, optimism. Real-time post-training data, ~5s freshness.",
      "priceUsd": 0.001
    },
    {
      "id": "dns.lookup",
      "method": "GET",
      "path": "/api/dns/lookup",
      "description": "Resolve a hostname over public DNS and return parsed records. Query: host (required FQDN), types (comma-separated: A,AAAA,MX,TXT,NS,CAA,SRV,CNAME,PTR,SOA — default A,AAAA,MX,TXT,NS), resolver (cloudflare|google|quad9|opendns, optional). Returns one normalized JSON shape per record type with per-type error pass-through. Reserved/local TLDs (.local, .internal, .invalid, .test, localhost) are rejected. 4s per-query timeout.",
      "priceUsd": 0.001
    },
    {
      "id": "domain.whois",
      "method": "GET",
      "path": "/api/domain/whois",
      "description": "Modern WHOIS via RDAP. Query: domain (e.g. example.com). Returns { domain, ldhName, handle, registrar:{ name, ianaId, url, abuseEmail, abusePhone }, registeredAt, expiresAt, updatedAt, statuses (camelCase ICANN EPP codes), nameservers[], dnssecSigned, rdapUrl }. GDPR: registrant personal data is generally redacted upstream and not returned. Some TLDs without RDAP are not supported and return 404 TLD_NOT_SUPPORTED.",
      "priceUsd": 0.001
    },
    {
      "id": "earth.now",
      "method": "GET",
      "path": "/api/earth/now",
      "description": "Situational awareness for a coordinate: recent earthquakes (USGS) and active wildfires (NIFC) within a configurable radius. Returns each with distance-from-query in km, sorted nearest-first. Multi-source synthesis from free US Government feeds. Real-time, post-training data.",
      "priceUsd": 0.0012
    },
    {
      "id": "geo.ip",
      "method": "GET",
      "path": "/api/geo/ip",
      "description": "Geolocate an IPv4/IPv6 address to country, region, city, and coordinates.",
      "priceUsd": 0.001
    },
    {
      "id": "geocode.address",
      "method": "GET",
      "path": "/api/geocode/address",
      "description": "Forward geocoding — free-text address or place name → latitude/longitude plus structured address components (houseNumber, road, suburb, city, county, state, postcode, country, countryCode). Query: q (2-500 chars), limit (1-10, default 5), country (optional 2-letter ISO 3166-1 bias). Underlying data is OpenStreetMap (ODbL). Sister: /api/geocode/reverse.",
      "priceUsd": 0.001
    },
    {
      "id": "geocode.reverse",
      "method": "GET",
      "path": "/api/geocode/reverse",
      "description": "Reverse geocoding — latitude/longitude → nearest formatted address plus structured components (houseNumber, road, suburb, city, county, state, postcode, country, countryCode). Query: lat (-90..90), lon (-180..180). Underlying data is OpenStreetMap (ODbL). Sister: /api/geocode/address.",
      "priceUsd": 0.001
    },
    {
      "id": "hash.compute",
      "method": "POST",
      "path": "/api/hash/compute",
      "description": "Compute one or more cryptographic digests (MD5, SHA-1, SHA-2 family, SHA-3 family, BLAKE2) of a string or hex/base64-encoded byte buffer. Returns hex or base64-encoded digests.",
      "priceUsd": 0.001
    },
    {
      "id": "image.compress",
      "method": "POST",
      "path": "/api/image/compress",
      "description": "Compress an image. POST exactly one of { url } or { imageBase64 }, plus optional { format?: auto|png|jpeg|webp|avif (default auto = keep input format), quality?: 1-100 (default 75), lossy?: bool (default true), effort?: 1-10 (default 6) }. Returns compressed image bytes directly with X-2s-* headers: Original-Bytes, Compressed-Bytes, Saved-Percent, Output-Format, Source-Format, Source-Width, Source-Height, Process-Ms. Limits: 5MB URL fetch, ~3MB inline body, 4096 × 4096 input pixels. Animated GIF input becomes animated WebP when format=webp or auto.",
      "priceUsd": 0.0024
    },
    {
      "id": "ipinfo.bulk",
      "method": "POST",
      "path": "/api/ipinfo/bulk",
      "description": "Geolocate up to 100 IPv4/IPv6 addresses in a single call. Returns per-IP results in input order; failed entries include an error object instead of geo fields.",
      "priceUsd": 0.006
    },
    {
      "id": "law.case-search",
      "method": "GET",
      "path": "/api/law/case-search",
      "description": "Search US court opinions (SCOTUS, federal circuits, state appellate/supreme — ~9M opinions). Query by free-text (party names, keywords, docket #, citation). Filter by court slug (e.g., \"scotus\", \"ca9\", \"nysupct\"), filing date range, and order (relevance/dateFiled-desc/dateFiled-asc/citeCount-desc). Returns clusterId, caseName, court, year, docket, reporter citations, citationCount, snippet, canonical URL. Discovery-side complement to case-verify. Backed by CourtListener (Free Law Project); underlying opinions are public domain.",
      "priceUsd": 0.0036
    },
    {
      "id": "law.case-verify",
      "method": "POST",
      "path": "/api/law/case-verify",
      "description": "Verify US legal case citations in a passage of text. POST { text } where text contains one or more citations (e.g. \"Marbury v. Madison, 5 U.S. 137 (1803)\"). Returns per-citation results with canonical case name, court, year, docket, citationCount, and a public CourtListener URL — or flags the citation as unverified. Anti-hallucination check for legal LLM output. Underlying opinions are public domain; CourtListener (Free Law Project) is the corpus.",
      "priceUsd": 0.006
    },
    {
      "id": "law.federal-register",
      "method": "GET",
      "path": "/api/law/federal-register",
      "description": "Search the US Federal Register — proposed rules, final rules, notices, and presidential documents. Filter by free-text term, document type (RULE/PRORULE/NOTICE/PRESDOCU), agency slug (e.g., epa, fda, sec), and publication date range. Returns document_number, type, title, abstract, FR citation, agencies, publication_date, effective_on, comments_close_on, htmlUrl, pdfUrl, rawTextUrl. Public-domain US government data. Real-time — published daily, past LLM training cutoff.",
      "priceUsd": 0.001
    },
    {
      "id": "law.opinion",
      "method": "POST",
      "path": "/api/law/opinion",
      "description": "Fetch the full text of a US court opinion by CourtListener opinion ID OR by citation. Returns plain text (preferred), HTML fallback, case metadata (case name, court, year, docket, citation), opinion type (lead/concurrence/dissent), author, and a list of alternate opinions in the same cluster. POST { opinionId?: number, citation?: string } — exactly one required. Anti-hallucination follow-up to case-verify: once you confirm the citation exists, fetch the text. Backed by CourtListener (public-domain underlying corpus).",
      "priceUsd": 0.0048
    },
    {
      "id": "law.sanctions-check",
      "method": "POST",
      "path": "/api/law/sanctions-check",
      "description": "Fuzzy-match a name (person, company, vessel, aircraft) against the US Treasury OFAC Specially Designated Nationals list. POST { query, threshold?, limit?, sourceList? }. Returns ranked matches with similarity scores, entity type, sanctions programs, aliases, and remarks. Threshold default 0.4; scores ≥ 0.85 flagged as hasHighConfidenceMatch. List refreshed daily from public US Treasury data.",
      "priceUsd": 0.0048
    },
    {
      "id": "papers.search",
      "method": "GET",
      "path": "/api/papers/search",
      "description": "Unified scientific literature search across arXiv (preprints), PubMed (biomedical), and Semantic Scholar (cross-field, with citation counts). Returns a flat array of papers with stable schema: source, sourceId, doi, title, authors, abstract, year, publishedAt, citationCount, url, pdfUrl. Partial failures surface in the errors array rather than failing the whole call. Optional filters: since (YYYY-MM-DD), sources (subset), limit (max 20 per source).",
      "priceUsd": 0.0024
    },
    {
      "id": "patents.detail",
      "method": "GET",
      "path": "/api/patents/detail",
      "description": "Full US patent application file-wrapper detail by application number. Returns bibliographic data (title, inventors, applicants, dates, status, examiner, art unit, docket #, confirmation #) plus the file-wrapper event timeline (filing, IDS, Office Actions, allowance, abandonment, …), continuity chain (parent / continuation / divisional / national stage), recorded assignments (assignor → assignee with reel/frame + conveyance text), and foreign priority claims under 35 USC § 119. Application number is the 6-10 digit USPTO ID (e.g. 18566276).",
      "priceUsd": 0.0018
    },
    {
      "id": "patents.documents",
      "method": "GET",
      "path": "/api/patents/documents",
      "description": "List every document in the file wrapper for a US patent application. Returns each document with its USPTO code (e.g. CTNF non-final OA, CTFR final OA, IDS, WCLM claims worksheet, NOA notice of allowance), human-readable description, official date, direction (INTERNAL/INCOMING/OUTGOING), and available formats with page counts. Includes patentCenterUrl pointing at the public USPTO Patent Center documents page for direct PDF download. Application number is the 6-10 digit USPTO ID.",
      "priceUsd": 0.0018
    },
    {
      "id": "patents.search",
      "method": "GET",
      "path": "/api/patents/search",
      "description": "Search US patent applications and grants via the USPTO Open Data Portal. Query: q (required, 2+ chars), yearFrom / yearTo (optional filing-year bounds), applicationType (optional: Utility|Design|Plant|Reissue), limit (1-100, default 10), offset (0-based, default 0). Returns { total, returned, offset, limit, hits[{ applicationNumber, title, applicationType, firstInventor, inventors[], applicants[], filingDate, effectiveFilingDate, status:{ code, description, updatedAt }, cpcSymbols[], uspcSymbol, url }] }. URLs link to USPTO Patent Center for the public file wrapper.",
      "priceUsd": 0.0018
    },
    {
      "id": "poi.near",
      "method": "GET",
      "path": "/api/poi/near",
      "description": "Find points of interest near a coordinate. Backed by OpenStreetMap via the Overpass API (free, public, ODbL). Returns name, OSM id (e.g. node/123 — deep-linkable to openstreetmap.org), latitude, longitude, distance in meters, composed street address (when present), phone, website, opening hours, brand, and cuisine tags. Results sorted nearest-first. Supported categories: restaurant, cafe, bar, fast_food, gas_station, ev_charging, parking, atm, bank, hospital, pharmacy, clinic, doctor, dentist, police, fire_station, post_office, library, toilets, school, university, supermarket, convenience, hotel, hostel, museum, attraction, park, playground. Query: lat (-90..90), lon (-180..180), category (one of the supported names), radius_m (1-10000, default 1000), limit (1-100, default 20).",
      "priceUsd": 0.001
    },
    {
      "id": "quakes.recent",
      "method": "GET",
      "path": "/api/quakes/recent",
      "description": "Recent earthquakes near a coordinate. Returns each quake with magnitude, place name, time (ISO), latitude/longitude/depth, tsunami flag, USGS event URL, and distance-from-query in km — sorted by time descending. Real-time data, post-LLM-training-cutoff. Backed by USGS FDSN event API (public domain). Query: lat (-90..90), lon (-180..180), radius_km (1-1000, default 500), hours (1-720, default 24), min_magnitude (0-10, default 2.0).",
      "priceUsd": 0.001
    },
    {
      "id": "sunrise.compute",
      "method": "GET",
      "path": "/api/sunrise/compute",
      "description": "Compute sunrise, sunset, solar noon, and civil/nautical/astronomical twilight times for a coordinate + date. Query: lat (-90..90), lon (-180..180), date (YYYY-MM-DD). All times returned as ISO 8601 UTC. At high latitudes near solstices an event may not occur (polar day/night) — those fields return null and a note is included. dayLengthMinutes is the sunrise→sunset interval.",
      "priceUsd": 0.001
    },
    {
      "id": "tides.now",
      "method": "GET",
      "path": "/api/tides/now",
      "description": "Next high/low tide predictions near a coordinate. Query: lat (-90..90), lon (-180..180), radius_km (1-500, default 100), hours (1-72, default 24). Returns { query, station:{ id, name, latitude, longitude, state, distanceKm }, predictions[{ time (station local), type: \"high\"|\"low\", heightMeters }], source }. Returns 404 NO_STATION if no NOAA tide station is within radius. Heights are referenced to MLLW (Mean Lower-Low Water).",
      "priceUsd": 0.001
    },
    {
      "id": "url.clean",
      "method": "GET",
      "path": "/api/url/clean",
      "description": "Fetch any URL and return the article content as clean markdown (with optional plain-text version). Strips nav, footer, ads, sidebars, scripts, styles, comments. Heuristic article extraction picks <article> / <main> / role=main / densest content block. SSRF-guarded, 512KB body cap, 8s timeout, 5 redirects max. Returns { url, finalUrl, title, markdown, text, wordCount, sourceBytes }. Sister to /api/url/unfurl (which returns metadata + 500-char preview); use clean when you want the FULL article for LLM consumption.",
      "priceUsd": 0.00108
    },
    {
      "id": "url.unfurl",
      "method": "GET",
      "path": "/api/url/unfurl",
      "description": "Fetch any URL and extract structured page metadata: title, description, og:image, canonical, favicon, site name, author, published time, language, and the first ~500 chars of body text. SSRF-guarded against private networks. 8s timeout, 512 KB max body. Returns the parsed metadata plus the raw og:/twitter:/itemprop meta dictionary for inspection.",
      "priceUsd": 0.001
    },
    {
      "id": "weather.zip",
      "method": "GET",
      "path": "/api/weather/zip",
      "description": "Current weather conditions for a US ZIP code (temperature, wind, humidity, conditions). Backed by the US National Weather Service (api.weather.gov) — public domain, no rate-limit pressure on commercial use.",
      "priceUsd": 0.0012
    },
    {
      "id": "wikipedia.summary",
      "method": "GET",
      "path": "/api/wikipedia/summary",
      "description": "Fetch a Wikipedia article summary in any of 30 supported languages. Returns title, displayTitle, lang, pageId, description, extract (plain text), extractHtml, lead image, canonical URLs, last-modified timestamp, word count, license, and an attribution string. Backed by https://<lang>.wikipedia.org/api/rest_v1/page/summary. Content is CC BY-SA 4.0 with attribution provided.",
      "priceUsd": 0.001
    }
  ]
}