{"openapi":"3.1.0","info":{"title":"PageWatch","version":"1.0.0","description":"Extract data from public static pages and monitor them for changes. Static HTML and JSON only. Payment for the paid endpoints: x402 v2, scheme exact, eip155:8453, USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, pay to 0x9f950fbeE661D8867750750F600Ff03fb7BAbe8D. Contact: zenith-ops@mail.grokbot.com","contact":{"name":"PageWatch","email":"zenith-ops@mail.grokbot.com","url":"https://pagewatch.erikssonanton2001.workers.dev/bot"},"license":{"name":"MIT","identifier":"MIT"},"x-guidance":"Use GET /v1/extract for one-off extraction (30 per day free). To watch a page, POST /v1/monitors and keep the manage_token; read changes from /m/{id}/events.json or feed.rss. The paid endpoints return HTTP 402 with a PAYMENT-REQUIRED header; sign the exact-scheme USDC payment and retry with PAYMENT-SIGNATURE (@x402/fetch does this). Errors are never charged."},"servers":[{"url":"https://pagewatch.erikssonanton2001.workers.dev"}],"components":{"securitySchemes":{"manageToken":{"type":"http","scheme":"bearer","description":"manage_token returned when the monitor was created."}}},"paths":{"/v1/extract":{"get":{"operationId":"extract","summary":"Extract data from one public page (free, 30 per day per client)","tags":["free"],"parameters":[{"name":"url","in":"query","required":true,"description":"Public http(s) page URL (ports 80/443, public DNS name).","example":"https://example.com/pricing","schema":{"type":"string"}},{"name":"mode","in":"query","required":false,"description":"What to extract. Default text.","example":"price","schema":{"type":"string","enum":["text","attr","list","table","price","events","page","links","json"]}},{"name":"selector","in":"query","required":false,"description":"CSS selector (max 300 characters). Required for text, attr and list.","example":"main h1","schema":{"type":"string"}},{"name":"attr","in":"query","required":false,"description":"Attribute name for mode=attr.","example":"href","schema":{"type":"string"}},{"name":"fields","in":"query","required":false,"description":"JSON object for mode=list: {\"name\":\"css\" or \"css@attr\"}, max 20 fields.","example":"{\"title\":\"h2\",\"link\":\"a@href\"}","schema":{"type":"string"}},{"name":"match","in":"query","required":false,"description":"Regular expression filter for mode=links.","example":"/docs/","schema":{"type":"string"}},{"name":"jsonpath","in":"query","required":false,"description":"JSONPath-lite for mode=json, for example $.items[0].price.","example":"$.items[0].price","schema":{"type":"string"}},{"name":"sameHost","in":"query","required":false,"description":"mode=links: only links on the page's own host (true/false).","example":"true","schema":{"type":"string"}},{"name":"all","in":"query","required":false,"description":"mode=text: return every match instead of the first (true/false).","example":"false","schema":{"type":"string"}},{"name":"tableIndex","in":"query","required":false,"description":"mode=table: zero-based index of the table to read.","example":"0","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"json (default), csv, or ics (events mode).","example":"json","schema":{"type":"string","enum":["json","csv","ics"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error (invalid input). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Error (blocked_by_robots). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Error (no_match / too_large). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Error (free_quota_exceeded). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Error (upstream failure). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/v1/monitors":{"post":{"operationId":"create_monitor","summary":"Create a monitor (free plan: min interval 60 min, 3 active per client, 30 days)","tags":["free"],"parameters":[],"responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error (invalid input). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"413":{"description":"Error (body_too_large). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Error (monitor_limit). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"503":{"description":"Error (capacity_reached). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"Public http(s) page URL.","example":"https://example.com/pricing"},"mode":{"type":"string","enum":["text","attr","list","table","price","events","page","links","json"],"description":"Extraction mode. Default page.","example":"price"},"selector":{"type":"string","description":"CSS selector."},"attr":{"type":"string","description":"Attribute name for mode=attr."},"fields":{"type":"object","description":"Field map for mode=list.","additionalProperties":{"type":"string"}},"match":{"type":"string","description":"Regular expression for mode=links."},"jsonpath":{"type":"string","description":"JSONPath-lite for mode=json."},"sameHost":{"type":"boolean"},"all":{"type":"boolean"},"tableIndex":{"type":"integer","minimum":0},"interval_minutes":{"type":"integer","description":"Check interval. Free: 60-10080 (default 360). Pro: 15-10080 (default 15)."},"webhook_url":{"type":"string","description":"https URL that receives a signed POST on every change."},"webhook_urls":{"type":"array","items":{"type":"string"},"description":"Pro plan only: up to 5 webhook URLs."}}}}}}}},"/v1/monitors/{id}":{"delete":{"operationId":"delete_monitor","summary":"Delete a monitor and its events","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Error (missing_token). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Error (invalid_token). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Error (not_found). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"security":[{"manageToken":[]}]}},"/v1/monitors/{id}/renew":{"post":{"operationId":"renew_monitor","summary":"Extend a free monitor by 30 days (re-activates expired or broken monitors)","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Error (missing_token). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Error (invalid_token). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Error (monitor_limit). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"security":[{"manageToken":[]}]}},"/v1/monitors/{id}/check-now":{"post":{"operationId":"check_now","summary":"Run a check immediately (once per 10 minutes)","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Error (missing_token). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Error (invalid_token). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Error (check_now_limited / host_throttled). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"security":[{"manageToken":[]}]}},"/m/{id}/events.json":{"get":{"operationId":"monitor_events","summary":"Change log of a monitor (public by id)","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Error (not_found). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/m/{id}/latest.json":{"get":{"operationId":"monitor_latest","summary":"Latest extracted value and status","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Error (not_found). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/m/{id}/feed.rss":{"get":{"operationId":"monitor_feed","summary":"RSS 2.0 feed of the latest 50 events","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Error (not_found). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/m/{id}/calendar.ics":{"get":{"operationId":"monitor_calendar","summary":"ICS calendar (events-mode monitors)","tags":["free"],"parameters":[{"name":"id","in":"path","required":true,"description":"Monitor id (32 hex characters).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Error (not_an_events_monitor). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Error (not_found). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/v1/pro/extract":{"get":{"operationId":"pro_extract","summary":"Extract data from a public page (pay per call)","description":"Same as the free /v1/extract but without the 30 requests per day limit: fetch one public static HTML or JSON page and return structured data (text, attr, list, table, price, events, page, links, json) as JSON, CSV or ICS. Honours robots.txt. No JavaScript rendering. Failed calls (4xx/5xx) are not settled.","tags":["paid"],"parameters":[{"name":"url","in":"query","required":true,"description":"Public http(s) page URL (ports 80/443, public DNS name).","example":"https://example.com/pricing","schema":{"type":"string"}},{"name":"mode","in":"query","required":false,"description":"What to extract. Default text.","example":"price","schema":{"type":"string","enum":["text","attr","list","table","price","events","page","links","json"]}},{"name":"selector","in":"query","required":false,"description":"CSS selector (max 300 characters). Required for text, attr and list.","example":"main h1","schema":{"type":"string"}},{"name":"attr","in":"query","required":false,"description":"Attribute name for mode=attr.","example":"href","schema":{"type":"string"}},{"name":"fields","in":"query","required":false,"description":"JSON object for mode=list: {\"name\":\"css\" or \"css@attr\"}, max 20 fields.","example":"{\"title\":\"h2\",\"link\":\"a@href\"}","schema":{"type":"string"}},{"name":"match","in":"query","required":false,"description":"Regular expression filter for mode=links.","example":"/docs/","schema":{"type":"string"}},{"name":"jsonpath","in":"query","required":false,"description":"JSONPath-lite for mode=json, for example $.items[0].price.","example":"$.items[0].price","schema":{"type":"string"}},{"name":"sameHost","in":"query","required":false,"description":"mode=links: only links on the page's own host (true/false).","example":"true","schema":{"type":"string"}},{"name":"all","in":"query","required":false,"description":"mode=text: return every match instead of the first (true/false).","example":"false","schema":{"type":"string"}},{"name":"tableIndex","in":"query","required":false,"description":"mode=table: zero-based index of the table to read.","example":"0","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"json (default), csv, or ics (events mode).","example":"json","schema":{"type":"string","enum":["json","csv","ics"]}}],"responses":{"200":{"description":"Success. Payment is settled.","content":{"application/json":{"schema":{"type":"object"},"example":{"url":"https://example.com/pricing","final_url":"https://example.com/pricing","fetched_at":"2026-10-17T08:00:00.000Z","mode":"price","data":{"price":1299.5,"currency":"SEK","availability":"InStock","name":"Example product","source":"json-ld"},"meta":{"matched":1,"truncated":false}}}}},"400":{"description":"Error (missing_url / invalid_url / invalid_mode / bad_selector / bad_params / blocked_target). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"402":{"description":"Payment required. The PAYMENT-REQUIRED header carries the x402 v2 requirements (base64 JSON)."},"403":{"description":"Error (blocked_by_robots). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Error (no_match / too_large / response_too_large). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Error (upstream_error / upstream_unreachable / robots_unavailable / redirect_blocked). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"504":{"description":"Error (upstream_timeout). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.002000"},"protocols":[{"x402":{}}]}}},"/v1/pro/monitors":{"post":{"operationId":"pro_monitors","summary":"Create a 30-day monitor with 15-minute checks (pay once)","description":"Creates a monitor that checks a public static page every 15 minutes (or slower) for 30 days and records every change. Up to 5 signed webhook URLs, an RSS feed, a JSON event log and (events mode) an ICS calendar. No per-client cap on the number of monitors; the global cap still applies. The response carries the manage token once. Failed calls (4xx/5xx) are not settled.","tags":["paid"],"parameters":[],"responses":{"201":{"description":"Success. Payment is settled.","content":{"application/json":{"schema":{"type":"object"},"example":{"id":"9f1c0b6e5d2a47c8b3e1a0f4d7c2b5a9","manage_token":"pwm_<shown once>","webhook_secret":"whsec_<shown once, only when a webhook was given>","feed_url":"https://pagewatch.erikssonanton2001.workers.dev/m/9f1c0b6e5d2a47c8b3e1a0f4d7c2b5a9/feed.rss","events_url":"https://pagewatch.erikssonanton2001.workers.dev/m/9f1c0b6e5d2a47c8b3e1a0f4d7c2b5a9/events.json","plan":"pro","interval_minutes":15,"expires_at":"2026-11-16T08:00:00.000Z"}}}},"400":{"description":"Error (missing_url / invalid_url / invalid_mode / bad_selector / bad_params / blocked_target). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"402":{"description":"Payment required. The PAYMENT-REQUIRED header carries the x402 v2 requirements (base64 JSON)."},"403":{"description":"Error (blocked_by_robots). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"413":{"description":"Error (body_too_large). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Error (no_match / too_large / response_too_large). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Error (upstream_error / upstream_unreachable / robots_unavailable / redirect_blocked). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"503":{"description":"Error (capacity_reached). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"504":{"description":"Error (upstream_timeout). Never charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"Public http(s) page URL.","example":"https://example.com/pricing"},"mode":{"type":"string","enum":["text","attr","list","table","price","events","page","links","json"],"description":"Extraction mode. Default page.","example":"price"},"selector":{"type":"string","description":"CSS selector."},"attr":{"type":"string","description":"Attribute name for mode=attr."},"fields":{"type":"object","description":"Field map for mode=list.","additionalProperties":{"type":"string"}},"match":{"type":"string","description":"Regular expression for mode=links."},"jsonpath":{"type":"string","description":"JSONPath-lite for mode=json."},"sameHost":{"type":"boolean"},"all":{"type":"boolean"},"tableIndex":{"type":"integer","minimum":0},"interval_minutes":{"type":"integer","description":"Check interval. Free: 60-10080 (default 360). Pro: 15-10080 (default 15)."},"webhook_url":{"type":"string","description":"https URL that receives a signed POST on every change."},"webhook_urls":{"type":"array","items":{"type":"string"},"description":"Pro plan only: up to 5 webhook URLs."}}}}}},"x-payment-info":{"price":{"mode":"fixed","currency":"USD","amount":"0.250000"},"protocols":[{"x402":{}}]}}}}}