{
  "openapi": "3.0.1",
  "info": {
    "title": "Website Change Monitor: AI Page Change & Pricing Alerts",
    "description": "First 25 changes free. Website change monitor, pay per qualified change — noise never charged by us: track website changes on competitor pricing pages and get alerts when a website changes, each with an AI summary and significance. Free demo on any plan; live check runs on your own Apify account.",
    "version": "0.3",
    "x-build-id": "nkAMNRMMg0OS6syIR"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/rich_minds~website-change-monitor-ai/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-rich_minds-website-change-monitor-ai",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/rich_minds~website-change-monitor-ai/runs": {
      "post": {
        "operationId": "runs-sync-rich_minds-website-change-monitor-ai",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/rich_minds~website-change-monitor-ai/run-sync": {
      "post": {
        "operationId": "run-sync-rich_minds-website-change-monitor-ai",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "startUrls": {
            "title": "Pages to watch",
            "type": "array",
            "description": "Competitor pages to watch — pricing, changelog, careers, terms. Each run compares every page with its last version (first run: its Internet Archive capture), one row per real change. Up to 50 static pages run on any Apify plan; more need a plan that runs Store Actors. Typed next to the free sample, they start the live check.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "preset": {
            "title": "Start from a ready watch list (one click)",
            "enum": [
              "custom",
              "competitor-pricing",
              "product-launches",
              "legal-policy",
              "hiring-signals",
              "docs-api-changes",
              "ecommerce-price-stock"
            ],
            "type": "string",
            "description": "Pick a job and press Start: it fills the goal, the categories, the significance bar and three public example pages you left empty, and compares them with the Internet Archive at once. Your own values always win. <b>Custom</b> = your own pages.",
            "default": "custom"
          },
          "goalDescription": {
            "title": "What matters to you?",
            "type": "string",
            "description": "What matters to you, in a sentence or two — the AI scores each change's relevance against it. Name your competitors (\"we compete with Notion and Slack\") or their domains (<code>notion.com</code>) and, with no <code>startUrls</code>, their pricing / changelog / careers pages are watched — the status lists them for you to keep."
          },
          "minScore": {
            "title": "Minimum score (0–100)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "The field that decides what you pay: changes scoring below this are dropped and <b>not charged</b>. Score = significance × 20 − 5 (1 → 15 … 5 → 95); with the AI it is blended with relevance to your goal. 35 = significance 2 and up.",
            "default": 35
          },
          "maxQualified": {
            "title": "Max changes to output",
            "minimum": 1,
            "maximum": 10000,
            "type": "integer",
            "description": "Hard cap on results — and the ceiling of what <b>this Actor</b> charges: at most this many × $0.015 with AI on (× $0.003 with AI off), e.g. 100 × $0.015 = $1.50. Changes over the cap are reported next run, never lost.",
            "default": 100
          },
          "maxDiscoveryChargeUsd": {
            "title": "Max source spend (USD)",
            "minimum": 0.01,
            "maximum": 1000,
            "type": "number",
            "description": "Hard cap passed to the Website Content Crawler run in <b>actor</b> mode — $0.50 in the form and for an API or agent call that leaves it out. The crawler bills platform usage, so the page cap <code>maxPagesPerRun</code> is what keeps a big section small.",
            "default": 0.5
          },
          "enableAi": {
            "title": "AI verdict per change",
            "type": "boolean",
            "description": "Category, significance, summary, before → after facts quoted from the page, relevance to your goal and a recommended action per change. <b>On = $0.015 per qualified change + AI tokens; off = $0.003</b> (rule-based category, significance and price facts).",
            "default": true
          },
          "notifyEmail": {
            "title": "E-mail me the new changes (optional)",
            "type": "string",
            "description": "After every run with at least one new change, the digest (per competitor, most significant first, with links) is e-mailed here through Apify's send-mail Actor. Schedule the run weekly and only new changes reach your inbox. Never sent for the free demo."
          },
          "minSignificance": {
            "title": "Minimum significance (1–5)",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "Only changes at least this significant are delivered (1 trivial … 5 critical: a price or plan change is 4–5, a new blog post 1–2). Free filter — dropped changes are never charged.",
            "default": 2
          },
          "categories": {
            "title": "Only these categories",
            "type": "array",
            "description": "Deliver only changes of these kinds. Empty = every category.",
            "items": {
              "type": "string",
              "enum": [
                "pricing",
                "plan_packaging",
                "product_feature",
                "messaging",
                "legal_policy",
                "hiring",
                "content",
                "contact_team",
                "availability",
                "other"
              ],
              "enumTitles": [
                "Pricing",
                "Plans & packaging",
                "Product / features",
                "Messaging (title, hero, meta)",
                "Legal / policy",
                "Hiring",
                "Content (blog, news)",
                "Contact / team",
                "Availability / stock",
                "Other"
              ]
            },
            "default": []
          },
          "targetFlags": {
            "title": "Target flags (any of)",
            "type": "array",
            "description": "Only deliver changes with at least one of these flags, ranked higher with more of them. Leave empty to keep everything. An API call passes the flag names (<code>priceMoved</code> works too); an unknown name stops the run at once with the valid ones.",
            "items": {
              "type": "string",
              "enum": [
                "price_moved",
                "price_increase",
                "price_decrease",
                "plan_change",
                "new_feature",
                "legal_change",
                "hiring_signal",
                "new_page",
                "page_removed",
                "title_changed",
                "large_change",
                "docs_change",
                "wayback_baseline",
                "stock_change"
              ],
              "enumTitles": [
                "A price changed",
                "Every moved price went up",
                "Every moved price went down",
                "Plans, seats or tiers changed",
                "A launch / changelog entry was added",
                "Terms, privacy or DPA text changed",
                "A job opening was added or removed",
                "A new page appeared in a watched section",
                "A known page disappeared",
                "Title or meta description changed",
                "20 % or more of the text changed",
                "A docs / API page changed",
                "Compared with the Internet Archive capture",
                "Stock / availability changed"
              ]
            }
          },
          "suppressionList": {
            "title": "Never report",
            "type": "array",
            "description": "URLs (or their start), globs such as <code>*/blog/*</code>, domains or labels whose changes are never reported or charged.",
            "items": {
              "type": "string"
            }
          },
          "minChangedChars": {
            "title": "Ignore edits smaller than (characters) (API only)",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "API only — hidden on the form. An edit smaller than this is noise — not delivered, not charged. A moved price is never noise.",
            "default": 20
          },
          "ignoreTextPatterns": {
            "title": "Also ignore text matching",
            "type": "array",
            "description": "Regular expressions removed before comparing, on top of the built-in ones (dates, clock times, '5 min ago', view / like counters, © years, session tokens), e.g. <code>Only \\d+ left</code>.",
            "items": {
              "type": "string"
            }
          },
          "watchMode": {
            "title": "Watch mode",
            "enum": [
              "pages",
              "section"
            ],
            "type": "string",
            "description": "<b>pages</b> — only the listed pages. <b>section</b> — every page under each listed URL (<code>/blog</code>, <code>/changelog</code>, <code>/careers</code>): new pages are reported as <code>page_added</code>, pages gone in two successful runs as <code>page_removed</code>.",
            "default": "pages"
          },
          "sectionDepth": {
            "title": "Section depth (API only)",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "API only — hidden on the form. Section mode: how many links deep below each listed URL.",
            "default": 1
          },
          "maxPagesPerSection": {
            "title": "Max pages per section (API only)",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "API only — hidden on the form. Section mode: pages crawled per listed URL.",
            "default": 50
          },
          "maxPagesPerRun": {
            "title": "Max pages per run",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "Cost guard: the crawl never loads more pages than this (≈ $0.04 of platform usage for 200 pages with the default crawler).",
            "default": 200
          },
          "crawlerType": {
            "title": "Crawler",
            "enum": [
              "cheerio",
              "playwright:adaptive",
              "playwright:firefox"
            ],
            "type": "string",
            "description": "<b>cheerio</b> (plain HTTP) is the cheapest and fine for most pricing and legal pages. Pick a browser when the page builds its content with JavaScript (the diff comes back empty or 'blocked').",
            "default": "cheerio"
          },
          "fetcher": {
            "title": "Who reads the pages",
            "enum": [
              "auto",
              "builtin",
              "crawler"
            ],
            "type": "string",
            "description": "<b>auto</b> (default) — up to 50 listed pages with the plain-HTTP crawler are fetched by this Actor itself: any Apify plan, no second Actor, seconds for 30 pages; bigger lists, whole sections, browser crawlers and screenshots run Website Content Crawler, and if your plan refuses it the listed pages are fetched here instead. <b>builtin</b> — always fetch the listed pages here. <b>crawler</b> — always Website Content Crawler.",
            "default": "auto"
          },
          "baselineFrom": {
            "title": "First-run baseline",
            "enum": [
              "wayback",
              "none"
            ],
            "type": "string",
            "description": "<b>wayback</b> (default) — a page seen for the first time is compared with its latest Internet Archive capture, so your first run already shows what changed since then (one extra crawl per new page, at most 50). A page the archive never captured is stored, and the status names the run that shows its changes. <b>none</b> — only store the first version of each page.",
            "default": "wayback"
          },
          "historyBackfill": {
            "title": "Page history from the Internet Archive (months)",
            "minimum": 0,
            "maximum": 24,
            "type": "integer",
            "description": "Opt-in, e.g. <b>12</b>: for each watched page, one Internet Archive capture per month of the last N months is diffed in order — one dated row per past change (<code>baselineSource: wayback_history</code>) and a price timeline on the REPORT page, so the first run answers \"how has their pricing moved this year?\". $0.10 per page whose history holds at least one past change, once per page (never again on later runs). 0 = off.",
            "default": 0
          },
          "cssSelector": {
            "title": "Watch only this part of the page (CSS)",
            "type": "string",
            "description": "e.g. <code>.pricing-table</code> or <code>main</code> — everything else on the page is ignored."
          },
          "ignoreSelectors": {
            "title": "Ignore these elements (CSS) (API only)",
            "type": "string",
            "description": "API only — hidden on the form. Added to the crawler's default removals (nav, footer, dialogs), e.g. <code>.testimonials, .ticker</code>."
          },
          "waitForSelector": {
            "title": "Wait for element (browser crawlers) (API only)",
            "type": "string",
            "description": "API only — hidden on the form. A CSS selector the browser waits for before reading the page."
          },
          "useSitemaps": {
            "title": "Use sitemaps to find new pages (API only)",
            "type": "boolean",
            "description": "API only — hidden on the form. Section mode: also read the site's sitemap to find pages no link points to.",
            "default": false
          },
          "screenshots": {
            "title": "Save a screenshot (browser crawlers)",
            "type": "boolean",
            "description": "Adds <code>screenshotUrl</code> to each change row; browser crawlers only.",
            "default": false
          },
          "respectRobotsTxtFile": {
            "title": "Respect robots.txt (API only)",
            "type": "boolean",
            "description": "API only — hidden on the form. Skip pages the site's robots.txt disallows.",
            "default": false
          },
          "monitors": {
            "title": "Client watch lists",
            "type": "array",
            "description": "For agencies: several named watch lists in one run, each with its own goal, snapshot history, DIGEST record and webhook, e.g. <code>[{\"name\": \"client-a\", \"urls\": [\"https://rival.com/pricing\"], \"goal\": \"…\", \"webhookUrl\": \"https://…\", \"clientName\": \"Acme Inc.\", \"logoUrl\": \"https://…/logo.png\", \"agencyName\": \"Your Agency\"}]</code>. With <code>clientName</code> the entry also gets a white-label REPORT page under your agency's name (<code>REPORT-client-a</code>, $0.05 per client report on a run with new changes). The check runs Website Content Crawler on your Apify plan."
          },
          "llmProvider": {
            "title": "AI model access",
            "enum": [
              "apify",
              "byok"
            ],
            "type": "string",
            "description": "<b>Apify (no keys)</b> — the AI runs through Apify's built-in OpenRouter proxy; tokens are billed to your Apify account at OpenRouter's rates. <b>My own key</b> — use your OpenAI / Anthropic / Gemini / Groq key instead (the model is picked from the key): with a free Gemini / Groq key expect 1–3 AI verdicts per run (the rest keep the rule verdict at the basic price); a paid key (billing on) assesses every change. Own-key pace, measured 2026-09-27: ≈ 34 s per change with a free google:gemini-3.6-flash key (50 changes ≈ 1880 s), ≈ 62.7–160.9 s per change with a free groq:openai/gpt-oss-120b key (2 calls at a time, one after a rate limit), so 50 changes need a timeout of ≈ 8225 s.",
            "default": "apify"
          },
          "llmModel": {
            "title": "AI model (API only)",
            "type": "string",
            "description": "API only — hidden on the form. Leave empty for the default: <code>anthropic/claude-haiku-4.5</code> via Apify; with your own key the provider's model is picked from the key (a Gemini key runs <code>google:gemini-3.5-flash-lite</code>). Apify mode takes an OpenRouter slug such as <code>openai/gpt-4.1-mini</code>; own-key mode takes <code>provider:model</code>, e.g. <code>anthropic:claude-haiku-4-5-20251001</code>."
          },
          "llmApiKey": {
            "title": "Your API key (own-key mode only)",
            "type": "string",
            "description": "Required when <b>AI model access</b> is <i>My own API key</i>. Stored encrypted by Apify, never logged."
          },
          "aiCandidateMultiplier": {
            "title": "AI candidate pool (× max qualified) (API only)",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "API only — hidden on the form. How many changes the AI judges, as a multiple of <b>Max changes to output</b>: the best rule-scored changes first (every change at least one significance point under <code>minSignificance</code>), up to this × <code>maxQualified</code>.",
            "default": 2
          },
          "sendAlertsTo": {
            "title": "Send alerts to (Slack, Discord, Teams, Google Chat, Telegram or webhook)",
            "type": "string",
            "description": "Paste one or more URLs, one per line — the service is detected from the address: a Slack or Discord channel webhook, a Teams Workflows or Google Chat space webhook, your Telegram bot's send link (<code>https://api.telegram.org/bot&lt;token&gt;/sendMessage?chat_id=@yourchannel</code>) or any other https URL (Zapier, Make, n8n, your CRM), which gets the changes as JSON. After every run with at least one new change, the digest (per competitor, most significant first, with links) is posted there. Never sent for the free demo. Headers, batching and signing: <i>Delivery details</i>."
          },
          "slackWebhookUrl": {
            "title": "Slack incoming-webhook URL (API only)",
            "type": "string",
            "description": "API only — hidden on the form, where <code>sendAlertsTo</code> takes it. The Slack incoming-webhook URL the digest is posted to."
          },
          "discordWebhookUrl": {
            "title": "Discord channel webhook URL (API only)",
            "type": "string",
            "description": "API only — hidden on the form, where <code>sendAlertsTo</code> takes it. The Discord channel webhook URL the digest is posted to."
          },
          "teamsWebhookUrl": {
            "title": "Teams Workflows webhook URL (API only)",
            "type": "string",
            "description": "API only — hidden on the form, where <code>sendAlertsTo</code> takes it. The Teams Workflows webhook URL the digest is posted to."
          },
          "googleChatWebhookUrl": {
            "title": "Google Chat webhook URL (API only)",
            "type": "string",
            "description": "API only — hidden on the form, where <code>sendAlertsTo</code> takes it. The Google Chat webhook URL the digest is posted to."
          },
          "telegramUrl": {
            "title": "Telegram sendMessage link (API only)",
            "type": "string",
            "description": "API only — hidden on the form, where <code>sendAlertsTo</code> takes it. The bot's sendMessage link with its chat_id."
          },
          "webhookUrl": {
            "title": "Webhook URL (optional)",
            "type": "string",
            "description": "Qualified changes are POSTed here as JSON (Zapier, Make, n8n, your CRM). For Google Sheets / Slack you can also use Apify's built-in Integrations tab. Stored encrypted — Zapier / Make hook URLs carry their secret in the path."
          },
          "webhookHeaders": {
            "title": "Webhook headers (API only)",
            "type": "object",
            "description": "API only — hidden on the form. Extra HTTP headers for the webhook, e.g. <code>{\"Authorization\": \"Bearer …\"}</code>. Stored encrypted by Apify, never logged."
          },
          "webhookSecret": {
            "title": "Webhook signing secret (optional)",
            "type": "string",
            "description": "Any random string. Every webhook POST then carries <code>X-Signature: sha256=&lt;HMAC-SHA256 of the raw body with this secret&gt;</code>, so your endpoint can verify it came from this Actor. Stored encrypted by Apify, never logged."
          },
          "webhookBatchSize": {
            "title": "Webhook batch size (API only)",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "API only — hidden on the form. 1 = one POST per change the moment it is ready. Higher = one POST per N changes.",
            "default": 1
          },
          "dedupeAcrossRuns": {
            "title": "Never output the same change twice (API only)",
            "type": "boolean",
            "description": "API only — hidden on the form. Remembers every change you were charged for (in a named key-value store on your account), so re-running on the same pages or dataset never re-delivers or re-charges it.",
            "default": true
          },
          "dedupeStoreName": {
            "title": "Dedupe store name",
            "type": "string",
            "description": "Key-value store for the delivered-change memory. Left at the default, the memory is kept per watch list (source, pages, monitors): rewording <code>goalDescription</code> keeps it. Running it for several clients on one account, type one name per client (or use <code>monitors</code>).",
            "default": "website-change-monitor-ai-seen"
          },
          "dedupeTtlDays": {
            "title": "Deliver a change again after (days)",
            "minimum": 0,
            "maximum": 3650,
            "type": "integer",
            "description": "How long a delivered change stays remembered. A change that comes back after that many days (a promo price that returns every quarter) is delivered — and charged — again as a new change. 0 = never again.",
            "default": 90
          },
          "historyDatasetName": {
            "title": "Keep a running change log (dataset name)",
            "type": "string",
            "description": "Optional. Type a name (e.g. <code>website-change-monitor-log</code>) and every run appends its new changes — date, competitor, category, price before → after — to that named dataset on your account: one change log across months to connect to Google Sheets or your BI tool once. Empty = off. Costs nothing extra.",
            "default": ""
          },
          "outcomes": {
            "title": "Which changes did your team act on? (optional)",
            "type": "array",
            "description": "One line per change you followed up: <code>&lt;changeId, dedupeKey or page URL&gt; = acted</code> (or <code>= ignored</code>). Remembered per watch list; the digest and <code>OUTPUT.outcomes</code> then say \"your team acted on 12 of 20 changes marked\" — the return a schedule is kept for. Free.",
            "items": {
              "type": "string"
            }
          },
          "stateStoreName": {
            "title": "Snapshot store name (API only)",
            "type": "string",
            "description": "API only — hidden on the form. Named key-value store on your account with the last version of every watched page (one namespace per monitor). Keep it the same on every scheduled run; a new name starts a new baseline.",
            "default": "website-change-monitor-state"
          },
          "includeUnchangedRows": {
            "title": "Also save unchanged pages (API only)",
            "type": "boolean",
            "description": "API only — hidden on the form. Baseline, unchanged and noise pages go to a separate named dataset (<code>website-change-monitor-pages</code>) — free; the main dataset stays one row per change.",
            "default": false
          },
          "sourceMode": {
            "title": "Where do the pages come from?",
            "enum": [
              "actor",
              "dataset",
              "list"
            ],
            "type": "string",
            "description": "<b>actor</b> — check the pages live (≤ 50 static pages on any plan; more via Website Content Crawler). <b>dataset</b> — a crawler dataset you have. <b>list</b> — page texts you send; you pay only for the analysis. The chosen mode always runs; only the untouched sample next to typed pages switches to the live check. <code>{}</code> runs the free demo.",
            "default": "actor"
          },
          "autoSwitchToLive": {
            "title": "Typed pages next to the sample start the live check (API only)",
            "type": "boolean",
            "description": "API only — hidden on the form. On (default): pages typed next to the untouched sample start the live check (spend-capped; <code>OUTPUT.switchedToLive</code> names them). Off: the mode you send is the mode that runs — the sample stays the free demo and the status names the pages it did not check. API pipelines that must never start a paid read on their own: send <code>false</code>.",
            "default": true
          },
          "datasetId": {
            "title": "Dataset",
            "type": "string",
            "description": "Only for <b>dataset</b> mode: a Website Content Crawler dataset (any run you already schedule). Each page is compared with its stored snapshot like a live run."
          },
          "itemsList": {
            "title": "Pages (list mode)",
            "type": "array",
            "description": "Only for <b>list</b> mode: JSON array of pages — <code>url</code> and <code>text</code> (or <code>markdown</code>) at least; optional <code>title</code>, <code>label</code>, <code>loadedTime</code>, and a <code>previousText</code> to compare against instead of the stored snapshot."
          },
          "discoveryActorId": {
            "title": "Source Actor (advanced) (API only)",
            "type": "string",
            "description": "API only — hidden on the form. Actor used in <b>actor</b> mode. Any Actor whose output has Website Content Crawler's fields (<code>url</code>, <code>text</code> / <code>markdown</code>, <code>metadata.title</code>) works.",
            "default": "apify/website-content-crawler"
          },
          "discoveryInput": {
            "title": "Crawler input overrides (advanced)",
            "type": "object",
            "description": "Only for <b>actor</b> mode: keys merged over the Website Content Crawler input this Actor builds (e.g. <code>{\"proxyConfiguration\": {\"useApifyProxy\": true, \"apifyProxyGroups\": [\"RESIDENTIAL\"]}}</code>). Setting it sends the watch list to the crawler (a Store Actor on your Apify plan) instead of the built-in fetcher."
          },
          "discoveryTimeoutSecs": {
            "title": "Crawler run timeout, seconds (API only)",
            "minimum": 60,
            "maximum": 86400,
            "type": "integer",
            "description": "API only — hidden on the form. How long Website Content Crawler may run before its partial results are used. Raise it when the status says the source stopped early.",
            "default": 3600
          },
          "demoOnly": {
            "title": "Run only the free demo (API only)",
            "type": "boolean",
            "description": "API only — hidden on the form. On = the run is the free demo on the sample pages whatever else the input says — nothing is crawled or charged (<code>\"demo\": true</code> works too). <code>OUTPUT.mode</code> says what every run was: <code>demo</code>, <code>live</code>, <code>list</code> or <code>dataset</code>.",
            "default": false
          },
          "maxToProcess": {
            "title": "Max candidates to process (API only)",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "API only — hidden on the form. Upper bound on how many detected changes are scored in one run (the rest are reported next run). Default = 3 × max changes."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}