openapi: 3.0.3 info: title: 'WebChange Detector' description: 'This documentation aims to provide you with all the information you need to integrate WebChange Detector into your workflow.' version: 1.0.0 servers: - url: 'https://api.webchangedetector.com' tags: - name: 'AI Feedback Rules' description: 'Manage rules for ignoring recurring false positives in AI verification results.' - name: Account description: 'This object represents your account with WCD' - name: Batch description: 'This object represents Batches of Queues.' - name: Comparison description: 'This object represents the comparison between 2 `Screenshots` and how they differ.' - name: Group description: 'This object groups together a list of URLs and group wide settings for them.' - name: 'Monitoring Trigger' description: 'Starts a monitoring check for single pages when they change, e.g. when a post is saved in WordPress (trigger-based monitoring).' - name: Queue description: 'This object represents a log of taking screenshots, comparing screenshots and their status.' - name: Screenshot description: "This object represents the actual screenshot and the location it's stored at." - name: Subaccount description: 'This object represents a Subaccount' - name: Url description: 'This object represents a single URL and specific settings' - name: Webhook description: 'This object contains the webhook calls a user can set to be notified for various events.' - name: Website description: 'This object represents Websites.' components: securitySchemes: default: type: http scheme: bearer description: 'You can retrieve your token on webchangedetector.com or via the plugin.' security: - default: [] paths: /api/v2/ai-feedback-rules: get: summary: 'List AI Feedback Rules' operationId: listAIFeedbackRules description: 'Returns a paginated list of all `AiFeedbackRule` for the current user.' parameters: - in: query name: scope description: 'Filter by scope.' example: url required: false schema: type: string description: 'Filter by scope.' example: url enum: - url - group - website - in: query name: is_active description: 'Filter by active status.' example: true required: false schema: type: boolean description: 'Filter by active status.' example: true - in: query name: website_id description: 'Filter by website UUID.' example: 21cf8800-f906-4fa3-b1db-ed3d2977354d required: false schema: type: string description: 'Filter by website UUID.' example: 21cf8800-f906-4fa3-b1db-ed3d2977354d responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: url description: 'Slider showing different slide' region_context: bbox: x: 0 'y': 100 w: 1920 h: 300 is_active: true last_matched_at: null match_count: 0 url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: null website_id: null created_at: '2026-02-21 13:37:00' updated_at: '2026-02-21 13:37:00' properties: data: type: array example: - id: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: url description: 'Slider showing different slide' region_context: bbox: x: 0 'y': 100 w: 1920 h: 300 is_active: true last_matched_at: null match_count: 0 url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: null website_id: null created_at: '2026-02-21 13:37:00' updated_at: '2026-02-21 13:37:00' items: type: object properties: id: type: string example: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: type: string example: url description: type: string example: 'Slider showing different slide' region_context: type: object properties: bbox: type: object properties: x: type: integer example: 0 'y': type: integer example: 100 w: type: integer example: 1920 h: type: integer example: 300 is_active: type: boolean example: true last_matched_at: type: string example: null nullable: true match_count: type: integer example: 0 url_id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: type: string example: null nullable: true website_id: type: string example: null nullable: true created_at: type: string example: '2026-02-21 13:37:00' updated_at: type: string example: '2026-02-21 13:37:00' tags: - 'AI Feedback Rules' post: summary: 'Create AI Feedback Rule' operationId: createAIFeedbackRule description: "Creates a new `AiFeedbackRule` from a comparison region. The backend\nauto-resolves whether the group belongs to a website and sets the\nscope accordingly." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: url description: 'Slider showing different slide' region_context: bbox: x: 0 'y': 100 w: 1920 h: 300 is_active: true last_matched_at: null match_count: 0 url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: null website_id: null created_at: '2026-02-21 13:37:00' updated_at: '2026-02-21 13:37:00' properties: data: type: object properties: id: type: string example: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: type: string example: url description: type: string example: 'Slider showing different slide' region_context: type: object properties: bbox: type: object properties: x: type: integer example: 0 'y': type: integer example: 100 w: type: integer example: 1920 h: type: integer example: 300 is_active: type: boolean example: true last_matched_at: type: string example: null nullable: true match_count: type: integer example: 0 url_id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: type: string example: null nullable: true website_id: type: string example: null nullable: true created_at: type: string example: '2026-02-21 13:37:00' updated_at: type: string example: '2026-02-21 13:37:00' tags: - 'AI Feedback Rules' requestBody: required: true content: application/json: schema: type: object properties: type: type: string description: 'Feedback target. `visual` (default) trains the AI on a specific image region of a Comparison. `console` trains it on a browser-console log entry to ignore.' example: visual enum: - visual - console comparison_id: type: string description: 'UUID of the comparison containing the region.' example: 21cf8800-f906-4fa3-b1db-ed3d2977354d region_id: type: integer description: 'The region ID within the AI verification result.' example: 0 console_entry: type: string description: 'Verbatim console-log line to teach the AI to ignore. Required when `type=console`. Max 500 chars. This field is required when type is console. Must not be greater than 500 characters.' example: '[Vue warn]: Component is missing template or render function.' scope: type: string description: 'Scope for the rule: "url" for this URL only, "group_or_website" for all URLs.' example: url enum: - url - group_or_website required: - comparison_id - region_id - scope '/api/v2/ai-feedback-rules/{id}': put: summary: 'Update AI Feedback Rule' operationId: updateAIFeedbackRule description: 'Update the active status and/or scope of an `AiFeedbackRule`.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: url description: 'Slider showing different slide' region_context: null is_active: false last_matched_at: null match_count: 0 url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: null website_id: null created_at: '2026-02-21 13:37:00' updated_at: '2026-02-21 13:37:00' properties: data: type: object properties: id: type: string example: 21cf8800-f906-4fa3-b1db-ed3d2977354d scope: type: string example: url description: type: string example: 'Slider showing different slide' region_context: type: string example: null nullable: true is_active: type: boolean example: false last_matched_at: type: string example: null nullable: true match_count: type: integer example: 0 url_id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 group_id: type: string example: null nullable: true website_id: type: string example: null nullable: true created_at: type: string example: '2026-02-21 13:37:00' updated_at: type: string example: '2026-02-21 13:37:00' tags: - 'AI Feedback Rules' requestBody: required: false content: application/json: schema: type: object properties: is_active: type: boolean description: 'Set the active status of the rule.' example: false scope: type: string description: 'Change the scope: "url" for this URL only, "group_or_website" for all URLs.' example: url enum: - url - group_or_website delete: summary: 'Delete AI Feedback Rule' operationId: deleteAIFeedbackRule description: 'Permanently deletes an `AiFeedbackRule`.' parameters: [] responses: {} tags: - 'AI Feedback Rules' parameters: - in: path name: id description: 'The ID of the ai feedback rule.' example: non required: true schema: type: string - in: path name: ai_feedback_rule description: 'The UUID of the AI Feedback Rule.' example: 21cf8800-f906-4fa3-b1db-ed3d2977354d required: true schema: type: string /api/v2/account: get: summary: 'Get Account' operationId: getAccount description: 'Retrieves your Account. The fields `plan`, `plan_name`, `company` and `magic_login_secret` only come for full accounts (not sub accounts).' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 041c6528-783f-4e7e-b831-1a424ffeb8f3 name_first: Hans name_last: Hacker email: mail@example.com webhook_secret: zq3csqdst0txgo5qe9mkqsourrxo56wd is_subaccount: false account_level: 0 can_manage_subaccounts: false can_create_subaccounts: false plan_label: null invitation_accepted: true plan_features: ai_verification: true browser_console: true checks_done: 6982 checks_left: 3018 checks_limit: 10000 timezone: UTC status: active renewal_at: '2025-01-01 13:37:42' plan: agency plan_name: Agency company: 'ACME Ltd' magic_login_secret: WdKnLLcsDxpJdfmv properties: data: type: object properties: id: type: string example: 041c6528-783f-4e7e-b831-1a424ffeb8f3 name_first: type: string example: Hans name_last: type: string example: Hacker email: type: string example: mail@example.com webhook_secret: type: string example: zq3csqdst0txgo5qe9mkqsourrxo56wd is_subaccount: type: boolean example: false account_level: type: integer example: 0 can_manage_subaccounts: type: boolean example: false can_create_subaccounts: type: boolean example: false plan_label: type: string example: null nullable: true invitation_accepted: type: boolean example: true plan_features: type: object properties: ai_verification: type: boolean example: true browser_console: type: boolean example: true checks_done: type: integer example: 6982 checks_left: type: integer example: 3018 checks_limit: type: integer example: 10000 timezone: type: string example: UTC status: type: string example: active renewal_at: type: string example: '2025-01-01 13:37:42' plan: type: string example: agency plan_name: type: string example: Agency company: type: string example: 'ACME Ltd' magic_login_secret: type: string example: WdKnLLcsDxpJdfmv tags: - Account put: summary: 'Update Account' operationId: updateAccount description: "Updates your `Account` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 041c6528-783f-4e7e-b831-1a424ffeb8f3 name_first: Jane name_last: Doe email: mail@example.com webhook_secret: zq3csqdst0txgo5qe9mkqsourrxo56wd is_subaccount: false account_level: 0 can_manage_subaccounts: false can_create_subaccounts: false plan_label: null invitation_accepted: true plan_features: ai_verification: true browser_console: true checks_done: 42 checks_left: 1337 checks_limit: 1379 timezone: UTC status: active renewal_at: '2025-01-01 13:37:42' plan: agency plan_name: Agency company: 'ACME LLC' magic_login_secret: WdKnLLcsDxpJdfmv properties: data: type: object properties: id: type: string example: 041c6528-783f-4e7e-b831-1a424ffeb8f3 name_first: type: string example: Jane name_last: type: string example: Doe email: type: string example: mail@example.com webhook_secret: type: string example: zq3csqdst0txgo5qe9mkqsourrxo56wd is_subaccount: type: boolean example: false account_level: type: integer example: 0 can_manage_subaccounts: type: boolean example: false can_create_subaccounts: type: boolean example: false plan_label: type: string example: null nullable: true invitation_accepted: type: boolean example: true plan_features: type: object properties: ai_verification: type: boolean example: true browser_console: type: boolean example: true checks_done: type: integer example: 42 checks_left: type: integer example: 1337 checks_limit: type: integer example: 1379 timezone: type: string example: UTC status: type: string example: active renewal_at: type: string example: '2025-01-01 13:37:42' plan: type: string example: agency plan_name: type: string example: Agency company: type: string example: 'ACME LLC' magic_login_secret: type: string example: WdKnLLcsDxpJdfmv tags: - Account requestBody: required: false content: application/json: schema: type: object properties: name_first: type: string description: 'First Name' example: Jane name_last: type: string description: 'Last Name' example: Doe company: type: string description: 'Company Name' example: 'ACME LLC' /api/v2/account/stats: get: summary: 'Get Account Stats' operationId: getAccountStats description: "Returns aggregated statistics for the authenticated account, computed across\nALL groups and websites (not paginated).\n\n- `estimated_monthly_checks` (top-level): estimated monthly monitoring checks. Kept for backwards compatibility.\n- `monitoring`: enabled monitoring groups; website/url counts, monthly estimate, soonest next run.\n- `manual`: enabled manual (non-monitoring) groups with selected URLs; website/url counts and checks per run.\n- `auto_update`: websites with auto-update checks enabled; count, missing-email count, active weekdays, monthly forecast." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: estimated_monthly_checks: 4520 monitoring: websites: 12 urls: 84 estimated_monthly_checks: 4520 next_run_at: 1716900000 next_runs: - name: example.com domain: example.com next_run_at: 1716900000 - name: shop.example domain: shop.example next_run_at: 1716903600 trigger_websites: 1 manual: websites: 8 urls: 56 checks_per_run: 112 auto_update: websites_enabled: 9 missing_email: 1 active_weekdays: - Mon - Wed - Fri estimated_monthly_checks: 1947 next_runs: - name: example.com domain: example.com next_run_at: 1716900000 - name: shop.example domain: shop.example next_run_at: 1716986400 properties: data: type: object properties: estimated_monthly_checks: type: integer example: 4520 monitoring: type: object properties: websites: type: integer example: 12 urls: type: integer example: 84 estimated_monthly_checks: type: integer example: 4520 next_run_at: type: integer example: 1716900000 next_runs: type: array example: - name: example.com domain: example.com next_run_at: 1716900000 - name: shop.example domain: shop.example next_run_at: 1716903600 items: type: object properties: name: type: string example: example.com domain: type: string example: example.com next_run_at: type: integer example: 1716900000 trigger_websites: type: integer example: 1 manual: type: object properties: websites: type: integer example: 8 urls: type: integer example: 56 checks_per_run: type: integer example: 112 auto_update: type: object properties: websites_enabled: type: integer example: 9 missing_email: type: integer example: 1 active_weekdays: type: array example: - Mon - Wed - Fri items: type: string estimated_monthly_checks: type: integer example: 1947 next_runs: type: array example: - name: example.com domain: example.com next_run_at: 1716900000 - name: shop.example domain: shop.example next_run_at: 1716986400 items: type: object properties: name: type: string example: example.com domain: type: string example: example.com next_run_at: type: integer example: 1716900000 tags: - Account /api/v2/account/reactivate: post: summary: 'Reactivate Account' operationId: reactivateAccount description: "Re-activates an account that was paused due to inactivity, including all its subaccounts.\nOnly the account owner can re-activate; cancelled accounts cannot be re-activated this way." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 041c6528-783f-4e7e-b831-1a424ffeb8f3 name_first: Hans name_last: Hacker email: mail@example.com status: active renewal_at: '2025-01-01 13:37:42' properties: data: type: object properties: id: type: string example: 041c6528-783f-4e7e-b831-1a424ffeb8f3 name_first: type: string example: Hans name_last: type: string example: Hacker email: type: string example: mail@example.com status: type: string example: active renewal_at: type: string example: '2025-01-01 13:37:42' tags: - Account /api/v2/batches: get: summary: 'List Batches' operationId: listBatches description: "Returns a list of all `Batch`. The `Batches` are sorted by creation date, with\nthe most recent `Batches` appearing first.\n\n`source` is one of `manual`, `monitoring`, `auto_update`. `ai_summary` is `null` for accounts without the `ai-verification` feature; `ai_summary.overall_status` is one of `everything_ok`, `needs_attention`. `website_domains` lists the unique domains of the websites linked to the batch's queue groups (empty when no website is linked).\n\n`trigger_context` is set for trigger-based monitoring runs (`source` = `monitoring`, started e.g. by saving a post in WordPress) and `null` otherwise. It holds the trigger `type`, `first_triggered_at` and the checked `pages`; each page has its `url` and `triggered_at`, plus `title`, `post_id` and `editor` when the trigger reported them. `type` is `post_save` or `manual_trigger` (\"run monitoring now\"). A `manual_trigger` run also has `scope` (`url` or `all`) and `editor` when reported; with `scope` = `all` (the whole Group) `pages` is empty." parameters: - in: query name: above_threshold description: 'Only show Batches where there is a change detected between 2 screenshots.' example: false required: false schema: type: boolean description: 'Only show Batches where there is a change detected between 2 screenshots.' example: false - in: query name: from description: 'Start date for filter. Must be a valid date.' example: '2024-07-01' required: false schema: type: string description: 'Start date for filter. Must be a valid date.' example: '2024-07-01' - in: query name: to description: 'End date for filter, defaults to today. Must be a valid date.' example: '2024-07-04' required: false schema: type: string description: 'End date for filter, defaults to today. Must be a valid date.' example: '2024-07-04' - in: query name: status description: 'Comma separated list of Comparison status to filter for.' example: 'to_fix,false_positive' required: false schema: type: string description: 'Comma separated list of Comparison status to filter for.' example: 'to_fix,false_positive' - in: query name: queue_type description: 'Comma separated list of Queue types to filter for.' example: 'post,comparison' required: false schema: type: string description: 'Comma separated list of Queue types to filter for.' example: 'post,comparison' - in: query name: group_ids description: 'Comma separated list of Group IDs.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' required: false schema: type: string description: 'Comma separated list of Group IDs.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' - in: query name: urls description: 'Comma separated list of URL IDs to filter for.' example: 023c282c-6513-420a-a36b-a654312ab229 required: false schema: type: string description: 'Comma separated list of URL IDs to filter for.' example: 023c282c-6513-420a-a36b-a654312ab229 - in: query name: websites description: 'Comma separated list of Website IDs to filter for.' example: 023c282c-6513-420a-a36b-a654312ab229 required: false schema: type: string description: 'Comma separated list of Website IDs to filter for.' example: 023c282c-6513-420a-a36b-a654312ab229 - in: query name: source description: 'Comma separated list of Batch sources to filter for (manual, monitoring, auto_update).' example: 'manual,auto_update' required: false schema: type: string description: 'Comma separated list of Batch sources to filter for (manual, monitoring, auto_update).' example: 'manual,auto_update' responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 0d5f8108-51f1-4961-939a-2d33c7145918 name: Monitoring source: monitoring trigger_context: type: post_save first_triggered_at: '2024-07-29T13:30:12+00:00' pages: - url: example.com/about title: 'About us' post_id: 42 editor: Anna triggered_at: '2024-07-29T13:31:05+00:00' group_names: - 'example.com - Monitoring Checks' website_domains: - example.com sc_version: '2.0' finished_at: '2024-07-29 13:37:42' ai_summary: summary: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: needs_attention processing_time_ms: 1234 update_results: null comparisons_count: ok: 0 new: 1 false_positive: 0 to_fix: 0 above_threshold: 10 queues_count: failed: 0 browser_console_count: added: 1 removed: 0 mixed: 0 unchanged: 0 links: first: 'http://api.webchangedetector.test/api/v2/batches?page=1' last: 'http://api.webchangedetector.test/api/v2/batches?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/batches?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/batches' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: 0d5f8108-51f1-4961-939a-2d33c7145918 name: Monitoring source: monitoring trigger_context: type: post_save first_triggered_at: '2024-07-29T13:30:12+00:00' pages: - url: example.com/about title: 'About us' post_id: 42 editor: Anna triggered_at: '2024-07-29T13:31:05+00:00' group_names: - 'example.com - Monitoring Checks' website_domains: - example.com sc_version: '2.0' finished_at: '2024-07-29 13:37:42' ai_summary: summary: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: needs_attention processing_time_ms: 1234 update_results: null comparisons_count: ok: 0 new: 1 false_positive: 0 to_fix: 0 above_threshold: 10 queues_count: failed: 0 browser_console_count: added: 1 removed: 0 mixed: 0 unchanged: 0 items: type: object properties: id: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 name: type: string example: Monitoring source: type: string example: monitoring trigger_context: type: object properties: type: type: string example: post_save first_triggered_at: type: string example: '2024-07-29T13:30:12+00:00' pages: type: array example: - url: example.com/about title: 'About us' post_id: 42 editor: Anna triggered_at: '2024-07-29T13:31:05+00:00' items: type: object properties: url: type: string example: example.com/about title: type: string example: 'About us' post_id: type: integer example: 42 editor: type: string example: Anna triggered_at: type: string example: '2024-07-29T13:31:05+00:00' group_names: type: array example: - 'example.com - Monitoring Checks' items: type: string website_domains: type: array example: - example.com items: type: string sc_version: type: string example: '2.0' finished_at: type: string example: '2024-07-29 13:37:42' ai_summary: type: object properties: summary: type: string example: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: type: string example: needs_attention processing_time_ms: type: integer example: 1234 update_results: type: string example: null nullable: true comparisons_count: type: object properties: ok: type: integer example: 0 new: type: integer example: 1 false_positive: type: integer example: 0 to_fix: type: integer example: 0 above_threshold: type: integer example: 10 queues_count: type: object properties: failed: type: integer example: 0 browser_console_count: type: object properties: added: type: integer example: 1 removed: type: integer example: 0 mixed: type: integer example: 0 unchanged: type: integer example: 0 links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/batches?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/batches?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/batches?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/batches' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Batch '/api/v2/batches/{id}': get: summary: 'Get Batch' operationId: getBatch description: "Retrieves a `Batch` object identfied by their ID.\n\n`source` is one of `manual`, `monitoring`, `auto_update`. `ai_summary` is `null` for accounts without the `ai-verification` feature; `ai_summary.overall_status` is one of `everything_ok`, `needs_attention`. `website_domains` lists the unique domains of the websites linked to the batch's queue groups (empty when no website is linked). `trigger_context` is set for trigger-based monitoring runs and `null` otherwise (shape: see List Batches)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 0d5f8108-51f1-4961-939a-2d33c7145918 name: Foobar source: monitoring trigger_context: null group_names: - 'example.com - Monitoring Checks' website_domains: - example.com sc_version: '2.0' finished_at: '2024-07-29 13:37:42' ai_summary: summary: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: needs_attention processing_time_ms: 1234 update_results: null comparisons_count: ok: 0 new: 1 false_positive: 0 to_fix: 0 above_threshold: 10 queues_count: failed: 0 browser_console_count: added: 1 removed: 0 mixed: 0 unchanged: 0 properties: data: type: object properties: id: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 name: type: string example: Foobar source: type: string example: monitoring trigger_context: type: string example: null nullable: true group_names: type: array example: - 'example.com - Monitoring Checks' items: type: string website_domains: type: array example: - example.com items: type: string sc_version: type: string example: '2.0' finished_at: type: string example: '2024-07-29 13:37:42' ai_summary: type: object properties: summary: type: string example: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: type: string example: needs_attention processing_time_ms: type: integer example: 1234 update_results: type: string example: null nullable: true comparisons_count: type: object properties: ok: type: integer example: 0 new: type: integer example: 1 false_positive: type: integer example: 0 to_fix: type: integer example: 0 above_threshold: type: integer example: 10 queues_count: type: object properties: failed: type: integer example: 0 browser_console_count: type: object properties: added: type: integer example: 1 removed: type: integer example: 0 mixed: type: integer example: 0 unchanged: type: integer example: 0 tags: - Batch put: summary: 'Update Batch' operationId: updateBatch description: "Updates the specified `Batch` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 0d5f8108-51f1-4961-939a-2d33c7145918 name: Foobar source: monitoring trigger_context: null group_names: - 'example.com - Monitoring Checks' website_domains: - example.com sc_version: '2.0' finished_at: '2024-07-29 13:37:42' ai_summary: summary: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: needs_attention processing_time_ms: 1234 update_results: null comparisons_count: ok: 0 new: 1 false_positive: 0 to_fix: 0 above_threshold: 10 queues_count: failed: 0 browser_console_count: added: 1 removed: 0 mixed: 0 unchanged: 0 properties: id: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 name: type: string example: Foobar source: type: string example: monitoring trigger_context: type: string example: null nullable: true group_names: type: array example: - 'example.com - Monitoring Checks' items: type: string website_domains: type: array example: - example.com items: type: string sc_version: type: string example: '2.0' finished_at: type: string example: '2024-07-29 13:37:42' ai_summary: type: object properties: summary: type: string example: 'Pricing text updated and navigation menu restructured. New JS error on checkout may affect functionality.' overall_status: type: string example: needs_attention processing_time_ms: type: integer example: 1234 update_results: type: string example: null nullable: true comparisons_count: type: object properties: ok: type: integer example: 0 new: type: integer example: 1 false_positive: type: integer example: 0 to_fix: type: integer example: 0 above_threshold: type: integer example: 10 queues_count: type: object properties: failed: type: integer example: 0 browser_console_count: type: object properties: added: type: integer example: 1 removed: type: integer example: 0 mixed: type: integer example: 0 unchanged: type: integer example: 0 tags: - Batch requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The name of the Batch.' example: Foobar required: - name parameters: - in: path name: id description: 'The ID of the Batch.' example: 0d5f8108-51f1-4961-939a-2d33c7145918 required: true schema: type: string '/api/v2/batches/{id}/update-results': put: summary: 'Store Batch Update Results' operationId: storeBatchUpdateResults description: "Stores the WordPress update results (core / plugins / themes) that were applied\naround this `Batch`. The whole blob is replaced on every call, so the endpoint is\nidempotent and safe to retry.\n\nIt is accepted in ANY batch state (also while the batch is still running) and for\nANY `source`. Send it for an empty run too (`updates.core` = `null`, empty arrays,\n`summary.total_attempted` = `0`, `summary.status` = `completed`).\n\nFor a batch with `source` = `auto_update` this is what enables the Auto Update Check\nresult email: it is sent once the batch is finished AND the update results are stored,\nwhichever of the two happens last." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 0d5f8108-51f1-4961-939a-2d33c7145918 name: 'Auto Update Checks' source: auto_update trigger_context: null group_names: - 'example.com - On-Demand Checks' website_domains: - example.com sc_version: '2.0' finished_at: '2024-07-29 13:37:42' ai_summary: null update_results: timestamp: 1756800000 updates: core: null plugins: - slug: akismet name: 'Akismet Anti-Spam' from_version: '5.3' to_version: 5.3.1 success: true error: null messages: [] themes: [] summary: total_attempted: 1 successful: 1 failed: 0 status: completed comparisons_count: ok: 0 new: 1 false_positive: 0 to_fix: 0 above_threshold: 10 queues_count: failed: 0 browser_console_count: added: 1 removed: 0 mixed: 0 unchanged: 0 properties: data: type: object properties: id: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 name: type: string example: 'Auto Update Checks' source: type: string example: auto_update trigger_context: type: string example: null nullable: true group_names: type: array example: - 'example.com - On-Demand Checks' items: type: string website_domains: type: array example: - example.com items: type: string sc_version: type: string example: '2.0' finished_at: type: string example: '2024-07-29 13:37:42' ai_summary: type: string example: null nullable: true update_results: type: object properties: timestamp: type: integer example: 1756800000 updates: type: object properties: core: type: string example: null nullable: true plugins: type: array example: - slug: akismet name: 'Akismet Anti-Spam' from_version: '5.3' to_version: 5.3.1 success: true error: null messages: [] items: type: object properties: slug: type: string example: akismet name: type: string example: 'Akismet Anti-Spam' from_version: type: string example: '5.3' to_version: type: string example: 5.3.1 success: type: boolean example: true error: type: string example: null nullable: true messages: type: array example: [] themes: type: array example: [] summary: type: object properties: total_attempted: type: integer example: 1 successful: type: integer example: 1 failed: type: integer example: 0 status: type: string example: completed comparisons_count: type: object properties: ok: type: integer example: 0 new: type: integer example: 1 false_positive: type: integer example: 0 to_fix: type: integer example: 0 above_threshold: type: integer example: 10 queues_count: type: object properties: failed: type: integer example: 0 browser_console_count: type: object properties: added: type: integer example: 1 removed: type: integer example: 0 mixed: type: integer example: 0 unchanged: type: integer example: 0 tags: - Batch requestBody: required: true content: application/json: schema: type: object properties: timestamp: type: integer description: 'Unix timestamp of the update run.' example: 1756800000 updates: type: object description: 'The performed updates (`core`, `plugins`, `themes`).' example: [] properties: core: type: object description: 'WordPress core update, or `null` when core was not updated.' example: null properties: attempted: type: boolean description: '' example: false success: type: boolean description: '' example: false from_version: type: string description: 'Must not be greater than 50 characters.' example: ffedwkwaviftjjugsevy nullable: true to_version: type: string description: 'Must not be greater than 50 characters.' example: ngbutgcc nullable: true error: type: string description: 'Must not be greater than 500 characters.' example: onwobjtqxd nullable: true messages: type: array description: 'Must not be greater than 300 characters.' example: - fxmfjvovmwwgkmvimwsrikts items: type: string nullable: true plugins: type: array description: 'Updated plugins. Each item: `slug`, `name`, `from_version`, `to_version`, `success`, `error`, `messages`. Must not have more than 300 items.' example: null items: type: object properties: slug: type: string description: 'Must not be greater than 255 characters.' example: dioytihgpxcueki name: type: string description: 'Must not be greater than 255 characters.' example: w nullable: true from_version: type: string description: 'Must not be greater than 50 characters.' example: llevbfamjmfjgeajjecno nullable: true to_version: type: string description: 'Must not be greater than 50 characters.' example: tswjaujzraupjyzwjqccz nullable: true success: type: boolean description: '' example: false error: type: string description: 'Must not be greater than 500 characters.' example: dafzfdvqazwrdxsczvjxppxaq nullable: true messages: type: array description: 'Must not be greater than 300 characters.' example: - zdpdgymqmglrxcycatkpaa items: type: string required: - slug - success themes: type: array description: 'Updated themes. Same item shape as `updates.plugins`. Must not have more than 300 items.' example: null items: type: object properties: slug: type: string description: 'Must not be greater than 255 characters.' example: ev name: type: string description: 'Must not be greater than 255 characters.' example: xwczqwluaphhvhqc nullable: true from_version: type: string description: 'Must not be greater than 50 characters.' example: dudfnxlnvxfk nullable: true to_version: type: string description: 'Must not be greater than 50 characters.' example: qkadabvgwismyieqwbwf nullable: true success: type: boolean description: '' example: false error: type: string description: 'Must not be greater than 500 characters.' example: ybatabyimucfpdisbhjrtpogs nullable: true messages: type: array description: 'Must not be greater than 300 characters.' example: - ipvptwwwu items: type: string required: - slug - success summary: type: object description: 'Run summary (`total_attempted`, `successful`, `failed`, `status`).' example: [] properties: total_attempted: type: integer description: 'Must be at least 0.' example: 40 successful: type: integer description: 'Must be at least 0.' example: 23 failed: type: integer description: 'Must be at least 0.' example: 8 status: type: string description: 'One of `completed`, `completed_with_errors`, `failed`.' example: completed enum: - completed - completed_with_errors - failed required: - total_attempted - successful - failed - status required: - timestamp - updates - summary parameters: - in: path name: id description: 'The ID of the Batch.' example: 0d5f8108-51f1-4961-939a-2d33c7145918 required: true schema: type: string /api/v2/comparisons: get: summary: 'List Comparisons' operationId: listComparisons description: "Returns a list of all `Comparison`. The `Comparisons` are sorted by creation date, with\nthe most recent `Comparisons` appearing first.\n\n`batch_source` is one of `manual`, `monitoring`, `auto_update`. `batch_trigger_type` is `post_save` (a saved page started the monitoring run), `manual_trigger` (\"run monitoring now\") or `null` (scheduled monitoring and all non-monitoring runs). `browser_console_*` fields are `null` unless the account has the `browser-console-comparisons` feature. `ai_regions`, `ai_verification_status`, and `ai_verification_result` are `null` unless the account has the `ai-verification` feature; `ai_verification_status` is one of `pending`, `verified`, `failed`, `skipped`. A comparison whose before or after screenshot came back as a completely blank page is decided automatically, without AI analysis: it carries an `ai_verification_result` with the marker `capture_issue` (`after_blank`, `before_blank` or `both_blank`), a `summary` and `alerts`, and no `regions`. Only `after_blank` (the page went blank) is an alert: it sets `status = new` and `alerts = 1`. A page recovering (`before_blank`) or staying blank (`both_blank`) is recorded the same way but resolves to `status = ok` with `alerts = 0`, because there is no valid comparison to judge against a blank baseline." parameters: - in: query name: above_threshold description: 'Is a change detected between 2 screenshots.' example: false required: false schema: type: boolean description: 'Is a change detected between 2 screenshots.' example: false - in: query name: from description: 'Start date for filter. Must be a valid date.' example: '2024-07-01' required: false schema: type: string description: 'Start date for filter. Must be a valid date.' example: '2024-07-01' - in: query name: to description: 'End date for filter, defaults to today. Must be a valid date.' example: '2024-07-04' required: false schema: type: string description: 'End date for filter, defaults to today. Must be a valid date.' example: '2024-07-04' - in: query name: status description: 'Comma separated list of status to filter for.' example: 'to_fix,false_positive' required: false schema: type: string description: 'Comma separated list of status to filter for.' example: 'to_fix,false_positive' - in: query name: groups description: 'Comma separated list of group IDs.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' required: false schema: type: string description: 'Comma separated list of group IDs.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' - in: query name: batches description: 'Batch IDs.' example: '0d5f8108-51f1-4961-939a-2d33c7145918,1d5f8108-51f1-4961-939a-2d33c7145918' required: false schema: type: string description: 'Batch IDs.' example: '0d5f8108-51f1-4961-939a-2d33c7145918,1d5f8108-51f1-4961-939a-2d33c7145918' - in: query name: token description: '' example: autem required: false schema: type: string description: '' example: autem - in: query name: urls description: 'Comma separated list of URL UUIDs.' example: 023c282c-6513-420a-a36b-a654312ab229 required: false schema: type: string description: 'Comma separated list of URL UUIDs.' example: 023c282c-6513-420a-a36b-a654312ab229 - in: query name: websites description: 'Comma separated list of Website UUIDs.' example: 023c282c-6513-420a-a36b-a654312ab229 required: false schema: type: string description: 'Comma separated list of Website UUIDs.' example: 023c282c-6513-420a-a36b-a654312ab229 - in: query name: source description: 'Comma separated list of Batch sources to filter for (manual, monitoring, auto_update).' example: 'manual,auto_update' required: false schema: type: string description: 'Comma separated list of Batch sources to filter for (manual, monitoring, auto_update).' example: 'manual,auto_update' responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: '2025-01-01 13:37:00' screenshot_1_updated_at: '2025-01-01 13:37:01' screenshot_1_link: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: '2025-01-01 13:37:00' screenshot_2_updated_at: '2025-01-01 13:37:01' screenshot_2_link: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: Foobar device: mobile monitoring: true group: 023c282c-6513-420a-a36b-a654312ab229 group_name: Barfoo queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: 'https://storage.webchangedetector.com/folder/comparison.png' batch: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: 'Auto Update Checks' batch_source: monitoring batch_trigger_type: null difference_percent: 0.4 threshold: 0.2 status: new public_link: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: f00b4r url: 'https://example.com' url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: wordpress browser_console_added: null browser_console_removed: null browser_console_change: null ai_regions: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 ai_verification_status: verified ai_verification_result: capture_issue: null summary: 'Pricing text updated, may need review.' processing_time_ms: 1234 total_regions: 1 all_good: 0 not_sure: 0 alerts: 1 regions: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null console_analysis: null created_at: '2025-01-01 13:37:00' links: first: 'http://api.webchangedetector.test/api/v2/comparisons?page=1' last: 'http://api.webchangedetector.test/api/v2/comparisons?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/comparisons?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/comparisons' per_page: 15 to: 1 total: 1 above_threshold_count: 3 properties: data: type: array example: - id: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: '2025-01-01 13:37:00' screenshot_1_updated_at: '2025-01-01 13:37:01' screenshot_1_link: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: '2025-01-01 13:37:00' screenshot_2_updated_at: '2025-01-01 13:37:01' screenshot_2_link: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: Foobar device: mobile monitoring: true group: 023c282c-6513-420a-a36b-a654312ab229 group_name: Barfoo queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: 'https://storage.webchangedetector.com/folder/comparison.png' batch: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: 'Auto Update Checks' batch_source: monitoring batch_trigger_type: null difference_percent: 0.4 threshold: 0.2 status: new public_link: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: f00b4r url: 'https://example.com' url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: wordpress browser_console_added: null browser_console_removed: null browser_console_change: null ai_regions: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 ai_verification_status: verified ai_verification_result: capture_issue: null summary: 'Pricing text updated, may need review.' processing_time_ms: 1234 total_regions: 1 all_good: 0 not_sure: 0 alerts: 1 regions: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null console_analysis: null created_at: '2025-01-01 13:37:00' items: type: object properties: id: type: string example: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: type: string example: '2025-01-01 13:37:00' screenshot_1_updated_at: type: string example: '2025-01-01 13:37:01' screenshot_1_link: type: string example: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: type: string example: '2025-01-01 13:37:00' screenshot_2_updated_at: type: string example: '2025-01-01 13:37:01' screenshot_2_link: type: string example: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: type: string example: Foobar device: type: string example: mobile monitoring: type: boolean example: true group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 group_name: type: string example: Barfoo queue: type: string example: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: type: string example: 'https://storage.webchangedetector.com/folder/comparison.png' batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: type: string example: 'Auto Update Checks' batch_source: type: string example: monitoring batch_trigger_type: type: string example: null nullable: true difference_percent: type: number example: 0.4 threshold: type: number example: 0.2 status: type: string example: new public_link: type: string example: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: type: string example: f00b4r url: type: string example: 'https://example.com' url_id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: type: string example: wordpress browser_console_added: type: string example: null nullable: true browser_console_removed: type: string example: null nullable: true browser_console_change: type: string example: null nullable: true ai_regions: type: array example: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 items: type: object properties: id: type: integer example: 0 bbox: type: object properties: x: type: integer example: 120 'y': type: integer example: 340 w: type: integer example: 280 h: type: integer example: 64 pixel_count: type: integer example: 1840 ai_verification_status: type: string example: verified ai_verification_result: type: object properties: capture_issue: type: string example: null nullable: true summary: type: string example: 'Pricing text updated, may need review.' processing_time_ms: type: integer example: 1234 total_regions: type: integer example: 1 all_good: type: integer example: 0 not_sure: type: integer example: 0 alerts: type: integer example: 1 regions: type: array example: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null items: type: object properties: region_id: type: integer example: 0 category: type: string example: alert description: type: string example: 'Pricing changed from $9 to $12' confidence: type: number example: 0.92 reason: type: string example: 'Numeric price text changed in hero section' matched_feedback_rule: type: string example: null nullable: true console_analysis: type: string example: null nullable: true created_at: type: string example: '2025-01-01 13:37:00' links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/comparisons?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/comparisons?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/comparisons?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/comparisons' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 above_threshold_count: type: integer example: 3 tags: - Comparison '/api/v2/comparisons/{id}': get: summary: 'Get Comparison' operationId: getComparison description: "Retrieves a `Comparison` object identfied by their ID.\n\n`batch_source` is one of `manual`, `monitoring`, `auto_update`. `batch_trigger_type` is `post_save` (a saved page started the monitoring run), `manual_trigger` (\"run monitoring now\") or `null` (scheduled monitoring and all non-monitoring runs). `browser_console_*` fields are `null` unless the account has the `browser-console-comparisons` feature. `ai_regions`, `ai_verification_status`, and `ai_verification_result` are `null` unless the account has the `ai-verification` feature; `ai_verification_status` is one of `pending`, `verified`, `failed`, `skipped`. A comparison whose before or after screenshot came back as a completely blank page is decided automatically, without AI analysis: it carries an `ai_verification_result` with the marker `capture_issue` (`after_blank`, `before_blank` or `both_blank`), a `summary` and `alerts`, and no `regions`. Only `after_blank` (the page went blank) is an alert: it sets `status = new` and `alerts = 1`. A page recovering (`before_blank`) or staying blank (`both_blank`) is recorded the same way but resolves to `status = ok` with `alerts = 0`, because there is no valid comparison to judge against a blank baseline." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: '2025-01-01 13:37:00' screenshot_1_updated_at: '2025-01-01 13:37:01' screenshot_1_link: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: '2025-01-01 13:37:00' screenshot_2_updated_at: '2025-01-01 13:37:01' screenshot_2_link: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: Foobar device: mobile monitoring: true group: 023c282c-6513-420a-a36b-a654312ab229 group_name: Barfoo queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: 'https://storage.webchangedetector.com/folder/comparison.png' batch: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: 'Auto Update Checks' batch_source: monitoring batch_trigger_type: null difference_percent: 0.4 threshold: 0.2 status: new public_link: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: f00b4r url: 'https://example.com' url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: wordpress browser_console_added: null browser_console_removed: null browser_console_change: null ai_regions: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 ai_verification_status: verified ai_verification_result: capture_issue: null summary: 'Pricing text updated, may need review.' processing_time_ms: 1234 total_regions: 1 all_good: 0 not_sure: 0 alerts: 1 regions: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null console_analysis: null created_at: '2025-01-01 13:37:00' properties: data: type: object properties: id: type: string example: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: type: string example: '2025-01-01 13:37:00' screenshot_1_updated_at: type: string example: '2025-01-01 13:37:01' screenshot_1_link: type: string example: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: type: string example: '2025-01-01 13:37:00' screenshot_2_updated_at: type: string example: '2025-01-01 13:37:01' screenshot_2_link: type: string example: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: type: string example: Foobar device: type: string example: mobile monitoring: type: boolean example: true group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 group_name: type: string example: Barfoo queue: type: string example: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: type: string example: 'https://storage.webchangedetector.com/folder/comparison.png' batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: type: string example: 'Auto Update Checks' batch_source: type: string example: monitoring batch_trigger_type: type: string example: null nullable: true difference_percent: type: number example: 0.4 threshold: type: number example: 0.2 status: type: string example: new public_link: type: string example: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: type: string example: f00b4r url: type: string example: 'https://example.com' url_id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: type: string example: wordpress browser_console_added: type: string example: null nullable: true browser_console_removed: type: string example: null nullable: true browser_console_change: type: string example: null nullable: true ai_regions: type: array example: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 items: type: object properties: id: type: integer example: 0 bbox: type: object properties: x: type: integer example: 120 'y': type: integer example: 340 w: type: integer example: 280 h: type: integer example: 64 pixel_count: type: integer example: 1840 ai_verification_status: type: string example: verified ai_verification_result: type: object properties: capture_issue: type: string example: null nullable: true summary: type: string example: 'Pricing text updated, may need review.' processing_time_ms: type: integer example: 1234 total_regions: type: integer example: 1 all_good: type: integer example: 0 not_sure: type: integer example: 0 alerts: type: integer example: 1 regions: type: array example: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null items: type: object properties: region_id: type: integer example: 0 category: type: string example: alert description: type: string example: 'Pricing changed from $9 to $12' confidence: type: number example: 0.92 reason: type: string example: 'Numeric price text changed in hero section' matched_feedback_rule: type: string example: null nullable: true console_analysis: type: string example: null nullable: true created_at: type: string example: '2025-01-01 13:37:00' tags: - Comparison put: summary: 'Update Comparison' operationId: updateComparison description: "Updates the specified `Comparison` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged.\n\n`batch_source` is one of `manual`, `monitoring`, `auto_update`. `batch_trigger_type` is `post_save` (a saved page started the monitoring run), `manual_trigger` (\"run monitoring now\") or `null` (scheduled monitoring and all non-monitoring runs). `browser_console_*` fields are `null` unless the account has the `browser-console-comparisons` feature. `ai_regions`, `ai_verification_status`, and `ai_verification_result` are `null` unless the account has the `ai-verification` feature; `ai_verification_status` is one of `pending`, `verified`, `failed`, `skipped`. A comparison whose before or after screenshot came back as a completely blank page is decided automatically, without AI analysis: it carries an `ai_verification_result` with the marker `capture_issue` (`after_blank`, `before_blank` or `both_blank`), a `summary` and `alerts`, and no `regions`. Only `after_blank` (the page went blank) is an alert: it sets `status = new` and `alerts = 1`. A page recovering (`before_blank`) or staying blank (`both_blank`) is recorded the same way but resolves to `status = ok` with `alerts = 0`, because there is no valid comparison to judge against a blank baseline." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: '2025-01-01 13:37:00' screenshot_1_updated_at: '2025-01-01 13:37:01' screenshot_1_link: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: '2025-01-01 13:37:00' screenshot_2_updated_at: '2025-01-01 13:37:01' screenshot_2_link: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: Foobar device: mobile monitoring: true group: 023c282c-6513-420a-a36b-a654312ab229 group_name: Barfoo queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: 'https://storage.webchangedetector.com/folder/comparison.png' batch: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: 'Auto Update Checks' batch_source: monitoring batch_trigger_type: null difference_percent: 0.4 threshold: 0.2 status: new public_link: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: f00b4r url: 'https://example.com' url_id: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: wordpress browser_console_added: null browser_console_removed: null browser_console_change: null ai_regions: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 ai_verification_status: verified ai_verification_result: capture_issue: null summary: 'Pricing text updated, may need review.' processing_time_ms: 1234 total_regions: 1 all_good: 0 not_sure: 0 alerts: 1 regions: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null console_analysis: null created_at: '2025-01-01 13:37:00' properties: id: type: string example: 21cf8800-f906-4fa3-b1db-ed3d2977354d screenshot_1: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae screenshot_1_created_at: type: string example: '2025-01-01 13:37:00' screenshot_1_updated_at: type: string example: '2025-01-01 13:37:01' screenshot_1_link: type: string example: 'https://storage.webchangedetector.com/folder/screenshot1.png' screenshot_2: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadaf screenshot_2_created_at: type: string example: '2025-01-01 13:37:00' screenshot_2_updated_at: type: string example: '2025-01-01 13:37:01' screenshot_2_link: type: string example: 'https://storage.webchangedetector.com/folder/screenshot2.png' html_title: type: string example: Foobar device: type: string example: mobile monitoring: type: boolean example: true group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 group_name: type: string example: Barfoo queue: type: string example: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 link: type: string example: 'https://storage.webchangedetector.com/folder/comparison.png' batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 batch_name: type: string example: 'Auto Update Checks' batch_source: type: string example: monitoring batch_trigger_type: type: string example: null nullable: true difference_percent: type: number example: 0.4 threshold: type: number example: 0.2 status: type: string example: new public_link: type: string example: 'https://www.webchangedetector.com/show-change-detection?token=f00b4r' token: type: string example: f00b4r url: type: string example: 'https://example.com' url_id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 cms: type: string example: wordpress browser_console_added: type: string example: null nullable: true browser_console_removed: type: string example: null nullable: true browser_console_change: type: string example: null nullable: true ai_regions: type: array example: - id: 0 bbox: x: 120 'y': 340 w: 280 h: 64 pixel_count: 1840 items: type: object properties: id: type: integer example: 0 bbox: type: object properties: x: type: integer example: 120 'y': type: integer example: 340 w: type: integer example: 280 h: type: integer example: 64 pixel_count: type: integer example: 1840 ai_verification_status: type: string example: verified ai_verification_result: type: object properties: capture_issue: type: string example: null nullable: true summary: type: string example: 'Pricing text updated, may need review.' processing_time_ms: type: integer example: 1234 total_regions: type: integer example: 1 all_good: type: integer example: 0 not_sure: type: integer example: 0 alerts: type: integer example: 1 regions: type: array example: - region_id: 0 category: alert description: 'Pricing changed from $9 to $12' confidence: 0.92 reason: 'Numeric price text changed in hero section' matched_feedback_rule: null items: type: object properties: region_id: type: integer example: 0 category: type: string example: alert description: type: string example: 'Pricing changed from $9 to $12' confidence: type: number example: 0.92 reason: type: string example: 'Numeric price text changed in hero section' matched_feedback_rule: type: string example: null nullable: true console_analysis: type: string example: null nullable: true created_at: type: string example: '2025-01-01 13:37:00' tags: - Comparison requestBody: required: true content: application/json: schema: type: object properties: status: type: string description: 'Mark the comparison as a false positive, as fixed or simply ok.' example: false_positive enum: - false_positive - ok - to_fix required: - status parameters: - in: path name: id description: 'The ID of the Comparison.' example: 21cf8800-f906-4fa3-b1db-ed3d2977354d required: true schema: type: string /api/v2/groups: get: summary: 'List Groups' operationId: listGroups description: "Returns a list of all Groups. The Groups are sorted by creation date, with\nthe most recent Groups appearing first." parameters: - in: query name: per_page description: 'Maximum number of Groups per page.' example: 15 required: false schema: type: integer description: 'Maximum number of Groups per page.' example: 15 - in: query name: monitoring description: 'Filter to monitoring (`true`) or manual-checks (`false`) groups only. Omit to return both.' example: true required: false schema: type: boolean description: 'Filter to monitoring (`true`) or manual-checks (`false`) groups only. Omit to return both.' example: true - in: query name: ids description: '' example: - autem required: false schema: type: array description: '' example: - autem items: type: string responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 023c282c-6513-420a-a36b-a654312ab229 name: 'Example Group' monitoring: true enabled: true hour_of_day: 0 interval_in_h: 24 alert_emails: 'hello@example.com,test@foobar.com' css: null js: null cms: wordpress threshold: 0.2 urls_count: 42 selected_urls_count: 37 basic_auth_user: null has_basic_auth: false proxy_type: none proxy_country: us links: first: 'http://api.webchangedetector.test/api/v2/groups?page=1' last: 'http://api.webchangedetector.test/api/v2/groups?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/groups?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/groups' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: 023c282c-6513-420a-a36b-a654312ab229 name: 'Example Group' monitoring: true enabled: true hour_of_day: 0 interval_in_h: 24 alert_emails: 'hello@example.com,test@foobar.com' css: null js: null cms: wordpress threshold: 0.2 urls_count: 42 selected_urls_count: 37 basic_auth_user: null has_basic_auth: false proxy_type: none proxy_country: us items: type: object properties: id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 name: type: string example: 'Example Group' monitoring: type: boolean example: true enabled: type: boolean example: true hour_of_day: type: integer example: 0 interval_in_h: type: integer example: 24 alert_emails: type: string example: 'hello@example.com,test@foobar.com' css: type: string example: null nullable: true js: type: string example: null nullable: true cms: type: string example: wordpress threshold: type: number example: 0.2 urls_count: type: integer example: 42 selected_urls_count: type: integer example: 37 basic_auth_user: type: string example: null nullable: true has_basic_auth: type: boolean example: false proxy_type: type: string example: none proxy_country: type: string example: us links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/groups?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/groups?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/groups?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/groups' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Group post: summary: 'Create Group' operationId: createGroup description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 023c282c-6513-420a-a36b-a654312ab229 name: 'Example Group' monitoring: true enabled: true hour_of_day: 0 interval_in_h: 24 schedule_type: interval schedule_days: null quiet_hours_start: null quiet_hours_end: null triggers: [] alert_emails: 'hello@example.com,test@foobar.com' css: '.btn {visibility: none;}' js: '' cms: wordpress threshold: 0.2 urls_count: 42 selected_urls_count: 37 basic_auth_user: null has_basic_auth: false proxy_type: none proxy_country: us properties: data: type: object properties: id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 name: type: string example: 'Example Group' monitoring: type: boolean example: true enabled: type: boolean example: true hour_of_day: type: integer example: 0 interval_in_h: type: integer example: 24 schedule_type: type: string example: interval schedule_days: type: string example: null nullable: true quiet_hours_start: type: string example: null nullable: true quiet_hours_end: type: string example: null nullable: true triggers: type: array example: [] alert_emails: type: string example: 'hello@example.com,test@foobar.com' css: type: string example: '.btn {visibility: none;}' js: type: string example: '' cms: type: string example: wordpress threshold: type: number example: 0.2 urls_count: type: integer example: 42 selected_urls_count: type: integer example: 37 basic_auth_user: type: string example: null nullable: true has_basic_auth: type: boolean example: false proxy_type: type: string example: none proxy_country: type: string example: us tags: - Group requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Name of the Group.' example: 'Example Group' monitoring: type: boolean description: 'Defaults to false.' example: true enum: - 'true' - 'false' enabled: type: boolean description: 'Defaults to true.' example: true enum: - 'true' - 'false' hour_of_day: type: integer description: 'Which hour of the day are the auto updates executed. Defaults to 0' example: 0 interval_in_h: type: number description: 'One of the following intervals of the hour. Defaults to 24' example: 24 enum: - 0.25 - 0.5 - 3 - 6 - 12 - 24 schedule_type: type: string description: 'Schedule type: interval (default), weekly, monthly, or off (no scheduled runs, only triggers)' example: interval enum: - interval - weekly - monthly - 'off' schedule_days: type: array description: 'Days for weekly (1=Mon..7=Sun) or monthly (1-30 or "last") schedules' example: - 1 - 3 - 5 items: type: string quiet_hours_start: type: integer description: 'Hour (0-23) when quiet period starts. No checks during quiet hours.' example: 22 quiet_hours_end: type: integer description: 'Hour (0-23) when quiet period ends' example: 6 alert_emails: type: array description: 'A list of emails to notify. Defaults to the account email.' example: - hello@example.com - mail@example.com items: type: string cms: type: string description: 'Optional CMS hint used by the screenshot pipeline (e.g. `wordpress`). Allowed values: see `config/enums.cms`.' example: wordpress enum: - wordpress nullable: true basic_auth_user: type: string description: 'Username for HTTP Basic Authentication' example: admin basic_auth_password: type: string description: 'Password for HTTP Basic Authentication' example: secret123 proxy_type: type: string description: 'Proxy type to use for screenshots' example: none enum: - none - static - residential proxy_country: type: string description: 'Location code for residential proxy (2-letter). Defaults to the screenshot region when unset; reserved for future country-specific proxies.' example: enim screenshot_region: type: string description: "Region this group's screenshots are taken from. `auto` (default) auto-geolocates the target domain to the nearest region, then stores the resolved concrete value back in this field. `us`/`eu` pin the region explicitly (`eu` renders from an EU IP with lower latency for EU sites). Reading this field returns `auto` transiently right after create, then the resolved `us`/`eu`. Allowed values: see `config/enums.screenshot_region`." example: auto enum: - us - eu - auto screenshot_delay: type: integer description: 'Minimum seconds between consecutive screenshot dispatches for this group, per user (7-60). Higher values reduce load on the screenshoter and target site, useful for groups with many URLs. Must be at least 7. Must not be greater than 60.' example: 10 nullable: true default_desktop: type: boolean description: 'Activate newly synced URLs for desktop screenshots by default in this group. Applied only to URLs the next sync first assigns; existing assignments keep their flags.' example: false default_mobile: type: boolean description: 'Activate newly synced URLs for mobile screenshots by default in this group. Applied only to URLs the next sync first assigns; existing assignments keep their flags.' example: false triggers: type: array description: 'Events that start a monitoring check in addition to the schedule, e.g. saving a post in WordPress. Objects with `type` (post_save) and optional `scope` (url). Monitoring groups only.' example: - type: post_save scope: url items: type: object properties: type: type: string description: '' example: post_save enum: - post_save scope: type: string description: 'What the trigger checks: `url` = only the reported URLs. Defaults to `url`.' example: url enum: - url required: - type css: type: string description: 'CSS to be injected before the screenshot is taken for all URLs in this group' example: '.btn {visibility: none;}' js: type: string description: 'JavaScript to be injected before the screenshot is taken for all URLs in this group' example: '' threshold: type: numeric description: 'Difference in percent of when this counts as a change detection for all URLs in this group' example: 0.4 required: - name '/api/v2/groups/{id}': get: summary: 'Get Group' operationId: getGroup description: 'Retrieves a Group object identfied by their ID' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 023c282c-6513-420a-a36b-a654312ab229 name: 'Example Group' monitoring: true enabled: true hour_of_day: 0 interval_in_h: 24 alert_emails: 'hello@example.com,test@foobar.com' css: null js: null cms: wordpress threshold: 0.2 urls_count: 42 selected_urls_count: 37 basic_auth_user: null has_basic_auth: false proxy_type: none proxy_country: us properties: data: type: object properties: id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 name: type: string example: 'Example Group' monitoring: type: boolean example: true enabled: type: boolean example: true hour_of_day: type: integer example: 0 interval_in_h: type: integer example: 24 alert_emails: type: string example: 'hello@example.com,test@foobar.com' css: type: string example: null nullable: true js: type: string example: null nullable: true cms: type: string example: wordpress threshold: type: number example: 0.2 urls_count: type: integer example: 42 selected_urls_count: type: integer example: 37 basic_auth_user: type: string example: null nullable: true has_basic_auth: type: boolean example: false proxy_type: type: string example: none proxy_country: type: string example: us tags: - Group put: summary: 'Update Group' operationId: updateGroup description: "Updates the specified `Group` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 023c282c-6513-420a-a36b-a654312ab229 name: 'Example Group' monitoring: true enabled: true hour_of_day: 0 interval_in_h: 24 schedule_type: interval schedule_days: null quiet_hours_start: null quiet_hours_end: null triggers: [] alert_emails: 'hello@example.com,test@foobar.com' css: '.btn {visibility: none;}' js: '' cms: wordpress threshold: 0.2 urls_count: 42 selected_urls_count: 37 basic_auth_user: admin has_basic_auth: true proxy_type: static proxy_country: us properties: data: type: object properties: id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 name: type: string example: 'Example Group' monitoring: type: boolean example: true enabled: type: boolean example: true hour_of_day: type: integer example: 0 interval_in_h: type: integer example: 24 schedule_type: type: string example: interval schedule_days: type: string example: null nullable: true quiet_hours_start: type: string example: null nullable: true quiet_hours_end: type: string example: null nullable: true triggers: type: array example: [] alert_emails: type: string example: 'hello@example.com,test@foobar.com' css: type: string example: '.btn {visibility: none;}' js: type: string example: '' cms: type: string example: wordpress threshold: type: number example: 0.2 urls_count: type: integer example: 42 selected_urls_count: type: integer example: 37 basic_auth_user: type: string example: admin has_basic_auth: type: boolean example: true proxy_type: type: string example: static proxy_country: type: string example: us tags: - Group requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Name of the Group.' example: 'Example Group' monitoring: type: boolean description: 'Defaults to false.' example: true enum: - 'true' - 'false' enabled: type: boolean description: 'Defaults to true.' example: true enum: - 'true' - 'false' hour_of_day: type: integer description: 'Which hour of the day are the auto updates executed. Defaults to 0' example: 0 interval_in_h: type: number description: 'One of the following intervals of the hour. Defaults to 24' example: 24 enum: - 0.25 - 0.5 - 3 - 6 - 12 - 24 schedule_type: type: string description: 'Schedule type: interval (default), weekly, monthly, or off (no scheduled runs, only triggers)' example: interval enum: - interval - weekly - monthly - 'off' schedule_days: type: array description: 'Days for weekly (1=Mon..7=Sun) or monthly (1-30 or "last") schedules' example: - 1 - 3 - 5 items: type: string quiet_hours_start: type: integer description: 'Hour (0-23) when quiet period starts. No checks during quiet hours.' example: 22 quiet_hours_end: type: integer description: 'Hour (0-23) when quiet period ends' example: 6 alert_emails: type: array description: 'A list of emails to notify. Defaults to the account email.' example: - hello@example.com - mail@example.com items: type: string css: type: string description: 'CSS to be injected before the screenshot is taken for all URLs in this group' example: '.btn {visibility: none;}' js: type: string description: 'JavaScript to be injected before the screenshot is taken for all URLs in this group' example: '' threshold: type: numeric description: 'Difference in percent of when this counts as a change detection for all URLs in this group' example: 0.4 basic_auth_user: type: string description: 'Username for HTTP Basic Authentication' example: admin basic_auth_password: type: string description: 'Password for HTTP Basic Authentication' example: secret123 proxy_type: type: string description: 'Proxy type to use for screenshots' example: none enum: - none - static - residential proxy_country: type: string description: 'Location code for residential proxy (2-letter). Defaults to the screenshot region when unset; reserved for future country-specific proxies.' example: facilis screenshot_region: type: string description: "Region this group's screenshots are taken from. `auto` (default) auto-geolocates the target domain to the nearest region, then stores the resolved concrete value back in this field. `us`/`eu` pin the region explicitly (`eu` renders from an EU IP with lower latency for EU sites). Setting `auto` re-triggers detection; the API mirrors any region change onto the website's sibling detection group automatically. Allowed values: see `config/enums.screenshot_region`." example: auto enum: - us - eu - auto screenshot_delay: type: integer description: 'Minimum seconds between consecutive screenshot dispatches for this group, per user (7-60). Higher values reduce load on the screenshoter and target site, useful for groups with many URLs. Must be at least 7. Must not be greater than 60.' example: 10 nullable: true default_desktop: type: boolean description: 'Activate newly synced URLs for desktop screenshots by default in this group. Applied only to URLs the next sync first assigns; existing assignments keep their flags.' example: false default_mobile: type: boolean description: 'Activate newly synced URLs for mobile screenshots by default in this group. Applied only to URLs the next sync first assigns; existing assignments keep their flags.' example: false triggers: type: array description: 'Events that start a monitoring check in addition to the schedule, e.g. saving a post in WordPress. Objects with `type` (post_save) and optional `scope` (url). Monitoring groups only.' example: - type: post_save scope: url items: type: object properties: type: type: string description: '' example: post_save enum: - post_save scope: type: string description: 'What the trigger checks: `url` = only the reported URLs. Defaults to `url`.' example: url enum: - url required: - type delete: summary: 'Delete Group' operationId: deleteGroup description: "Permanently deletes a `Group`. This cannot be undone.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: '{ID} deleted' properties: message: type: string example: '{ID} deleted' tags: - Group parameters: - in: path name: id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string '/api/v2/groups/{id}/add-urls': post: summary: 'Add Urls To Group' operationId: addUrlsToGroup description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: count: '{Amount of URLs added}' properties: count: type: string example: '{Amount of URLs added}' tags: - Group requestBody: required: true content: application/json: schema: type: object properties: urls: type: array description: 'Array of URLs with their settings in this Group' example: - id: 418e0748-a9cf-480b-86d6-88b00bac00b9 desktop: true - id: 418e0748-a9cf-480b-86d6-88b00bac00c1 mobile: false items: type: string required: - urls parameters: - in: path name: id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string '/api/v2/groups/{id}/remove-urls': post: summary: 'Remove Urls From Group' operationId: removeUrlsFromGroup description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: count: '{Amount of URLs removed}' properties: count: type: string example: '{Amount of URLs removed}' tags: - Group requestBody: required: true content: application/json: schema: type: object properties: urls: type: array description: 'Array of URL IDs' example: - 418e0748-a9cf-480b-86d6-88b00bac00b9 - 418e0748-a9cf-480b-86d6-88b00bac00c1 items: type: string required: - urls parameters: - in: path name: id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string '/api/v2/groups/{id}/urls': get: summary: 'List Urls For Group' operationId: listUrlsForGroup description: 'Returns a list of all `Urls`. The `Urls` are sorted by creation date, with the most recent `Urls` appearing first.' parameters: - in: query name: per_page description: 'Maximum number of URLs per page.' example: 25 required: false schema: type: integer description: 'Maximum number of URLs per page.' example: 25 - in: query name: type description: 'Filter by post-type slug (e.g. `posts`, `pages`, `products`).' example: posts required: false schema: type: string description: 'Filter by post-type slug (e.g. `posts`, `pages`, `products`).' example: posts - in: query name: category description: 'Filter by URL category (e.g. `types`, `taxonomies`, `frontpage`).' example: types required: false schema: type: string description: 'Filter by URL category (e.g. `types`, `taxonomies`, `frontpage`).' example: types - in: query name: search description: 'Substring match against the URL or its title.' example: about required: false schema: type: string description: 'Substring match against the URL or its title.' example: about - in: query name: url_ids description: 'Comma-separated list of URL UUIDs to restrict the result to.' example: '91e9c9fd-b86f-4269-a3f4-f02810167a6d,b3a9d2e5-2c64-4a16-8f1c-9e3b21f8a4e7' required: false schema: type: string description: 'Comma-separated list of URL UUIDs to restrict the result to.' example: '91e9c9fd-b86f-4269-a3f4-f02810167a6d,b3a9d2e5-2c64-4a16-8f1c-9e3b21f8a4e7' responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' desktop: true mobile: true css: null js: null threshold: null group: 023c282c-6513-420a-a36b-a654312ab229 links: first: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls?page=1' last: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls' per_page: 15 to: 1 total: 1 selected_urls_count: 1 properties: data: type: array example: - id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' desktop: true mobile: true css: null js: null threshold: null group: 023c282c-6513-420a-a36b-a654312ab229 items: type: object properties: id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: type: string example: 'Example Title' url: type: string example: example.com/foobar last_crawled_at: type: string example: '2025-01-01 13:37:42' desktop: type: boolean example: true mobile: type: boolean example: true css: type: string example: null nullable: true js: type: string example: null nullable: true threshold: type: string example: null nullable: true group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/groups/023c282c-6513-420a-a36b-a654312ab229/urls' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 selected_urls_count: type: integer example: 1 tags: - Group parameters: - in: path name: id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string - in: path name: type description: 'URL Type.' example: foobar required: true schema: type: string - in: path name: category description: Category. example: barfoo required: true schema: type: string - in: path name: search description: 'Search in html_title and url.' example: loremipsum required: true schema: type: string - in: path name: url_ids description: 'Comma separated list of URL UUIDs' example: eos required: true schema: type: string '/api/v2/groups/{group_id}/urls/select-all': put: summary: 'Select All Urls In Group' operationId: selectAllUrlsInGroup description: "Enables or disables one viewport (desktop or mobile) for ALL URLs of a group in a single\noperation. Use this instead of sending thousands of individual URL ids when toggling a whole\ncolumn (\"select all\" / \"deselect all\"). Only the given device column changes; the other viewport\nis left untouched." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'All desktop URLs in Group 023c282c-6513-420a-a36b-a654312ab229 updated' selected_urls_count: 42 selected_checks_count: 80 properties: message: type: string example: 'All desktop URLs in Group 023c282c-6513-420a-a36b-a654312ab229 updated' selected_urls_count: type: integer example: 42 selected_checks_count: type: integer example: 80 tags: - Group requestBody: required: true content: application/json: schema: type: object properties: device: type: string description: 'Which viewport to toggle for every URL.' example: desktop enum: - desktop - mobile enabled: type: boolean description: 'Whether screenshots of that viewport should be taken.' example: true enum: - 'true' - 'false' required: - device - enabled parameters: - in: path name: group_id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string '/api/v2/groups/{group_id}/urls/{url_id}': put: summary: 'Update Url In Group' operationId: updateUrlInGroup description: 'Updates a URL within a group.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' desktop: true mobile: true css: '.btn {visibility: none;}' js: null threshold: null group: 023c282c-6513-420a-a36b-a654312ab229 meta: selected_urls_count: 1 properties: data: type: object properties: id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: type: string example: 'Example Title' url: type: string example: example.com/foobar last_crawled_at: type: string example: '2025-01-01 13:37:42' desktop: type: boolean example: true mobile: type: boolean example: true css: type: string example: '.btn {visibility: none;}' js: type: string example: null nullable: true threshold: type: string example: null nullable: true group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 meta: type: object properties: selected_urls_count: type: integer example: 1 tags: - Group requestBody: required: false content: application/json: schema: type: object properties: desktop: type: boolean description: 'Should a desktop screenshot be taken' example: true enum: - 'true' - 'false' mobile: type: boolean description: 'Should a mobile screenshot be taken' example: true enum: - 'true' - 'false' css: type: string description: 'CSS to be injected before the screenshot is taken' example: '.btn {visibility: none;}' js: type: string description: 'JavaScript to be injected before the screenshot is taken' example: illum threshold: type: numeric description: 'Difference in percent of when this counts as a change detection' example: 0.4 parameters: - in: path name: group_id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string - in: path name: url_id description: 'The ID of the URL in that Group.' example: 418e0748-a9cf-480b-86d6-88b00bac00b9 required: true schema: type: string '/api/v2/groups/{group_id}/urls': put: summary: 'Update All Urls In Group' operationId: updateAllUrlsInGroup description: 'Updates all URLs within a group.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: '42 URLs in Group 023c282c-6513-420a-a36b-a654312ab229 changed' properties: message: type: string example: '42 URLs in Group 023c282c-6513-420a-a36b-a654312ab229 changed' tags: - Group requestBody: required: false content: application/json: schema: type: object properties: urls: type: array description: 'Array of URLs with settings' example: - id: 418e0748-a9cf-480b-86d6-88b00bac00b9 desktop: true mobile: true css: null js: null threshold: 0.4 items: type: string parameters: - in: path name: group_id description: 'The ID of the Group.' example: 023c282c-6513-420a-a36b-a654312ab229 required: true schema: type: string /api/v2/monitoring/trigger: post: summary: 'Trigger Monitoring Check' operationId: triggerMonitoringCheck description: "Reports changed pages of a monitoring `Group`. After a short wait (so caches serve the new\nversion) a monitoring check runs for exactly these pages and compares them against their last\nmonitoring screenshot, with the Group's usual alerts and webhooks. Further triggers for the same\npage during the wait are merged into one check.\n\nThe Group must be an enabled monitoring Group with the trigger `type` in its `triggers`.\nOnly URLs that are active in the Group are checked, the others are listed under `ignored`\n(`not_in_group`, `not_active`, `rate_limited`). Nothing is charged for ignored URLs.\nAt most 60 pages per Group and hour are accepted; a request with only pages over that\ncap gets 429.\n\n**`type` = `manual_trigger` (\"run monitoring now\")** starts the monitoring check immediately,\nwithout the wait, the hourly cap or the merging described above. The check runs as soon as\nthe request returns, so clear or warm the page caches first, then call this endpoint.\nSend `scope` = `all` (and no `urls`) to check every active URL of the Group, or `scope` =\n`url` with `urls`. The Group only has to be an enabled monitoring Group; `manual_trigger` is\nnot configured in `triggers`. All URLs are checked in one monitoring run (`batch_id`, with\n`trigger_context.type` = `manual_trigger`); `run_at` is its start. URLs with a monitoring\ncheck in progress are listed under `ignored` (`already_running`). Waiting `post_save`\nchecks of the started URLs are replaced by this run.\nErrors carry a `reason`: 409 `already_running` (every URL is already being checked, or a\nrun for this Group is being started right now), 402 `not_enough_credits` (the checks do\nnot fit into the remaining checks; nothing is started), 422 `unsupported` (none of the URLs\ncan be checked), 422 `trigger_not_enabled` (not an enabled monitoring Group)." parameters: [] responses: 202: description: '' content: application/json: schema: oneOf: - description: post_save type: object example: data: group_id: 023c282c-6513-420a-a36b-a654312ab229 type: post_save accepted: - example.com/about ignored: - url: 'https://example.com/new-post/' reason: not_in_group run_at: '2026-09-25T10:05:00.000000Z' properties: data: type: object properties: group_id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 type: type: string example: post_save accepted: type: array example: - example.com/about items: type: string ignored: type: array example: - url: 'https://example.com/new-post/' reason: not_in_group items: type: object properties: url: type: string example: 'https://example.com/new-post/' reason: type: string example: not_in_group run_at: type: string example: '2026-09-25T10:05:00.000000Z' - description: manual_trigger type: object example: data: group_id: 023c282c-6513-420a-a36b-a654312ab229 type: manual_trigger accepted: - example.com/about - example.com/contact ignored: - url: example.com/news reason: already_running run_at: '2026-09-25T10:00:03.000000Z' batch_id: 0d5f8108-51f1-4961-939a-2d33c7145918 properties: data: type: object properties: group_id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 type: type: string example: manual_trigger accepted: type: array example: - example.com/about - example.com/contact items: type: string ignored: type: array example: - url: example.com/news reason: already_running items: type: object properties: url: type: string example: example.com/news reason: type: string example: already_running run_at: type: string example: '2026-09-25T10:00:03.000000Z' batch_id: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 402: description: 'manual_trigger, not enough checks left' content: application/json: schema: type: object example: message: 'Bummer, you used your credit already. Please upgrade your account to a bigger plan.' reason: not_enough_credits properties: message: type: string example: 'Bummer, you used your credit already. Please upgrade your account to a bigger plan.' reason: type: string example: not_enough_credits 409: description: 'manual_trigger, every URL already being checked' content: application/json: schema: type: object example: message: 'A monitoring check is already running for these pages.' reason: already_running properties: message: type: string example: 'A monitoring check is already running for these pages.' reason: type: string example: already_running tags: - 'Monitoring Trigger' requestBody: required: true content: application/json: schema: type: object properties: group_id: type: string description: 'ID of the monitoring Group the URLs belong to. The Group must have the trigger `type` in its `triggers`. Must not be greater than 36 characters.' example: 023c282c-6513-420a-a36b-a654312ab229 type: type: string description: 'What happened. Allowed values: see `config/enums.trigger_type`: `post_save` (a page was saved; checked after a short wait) or `manual_trigger` (run the monitoring now; the check starts immediately).' example: post_save enum: - post_save - manual_trigger scope: type: string description: 'What to check: `url` (default) = only the given `urls`; `all` = every active URL of the Group, without `urls`. `all` is allowed with `type` = `manual_trigger` only.' example: url enum: - url - all urls: type: array description: 'The changed pages, max. 50 per request. Only URLs that are active in the Group are checked; others are returned under `ignored`. Required unless `scope` is `all`; not allowed with `scope` = `all`.' example: - url: 'https://example.com/about/' title: 'About us' post_id: 42 items: type: object properties: url: type: string description: 'The page URL, with or without protocol and trailing slash. Must not be greater than 2048 characters.' example: 'https://example.com/about/' title: type: string description: "Optional page title, shown in the run's `trigger_context`. Must not be greater than 255 characters." example: 'About us' nullable: true post_id: type: integer description: 'Optional CMS id of the page (e.g. the WordPress post ID), stored in `trigger_context`. Must be at least 1.' example: 42 nullable: true required: - url editor: type: string description: 'Optional display name of the person who made the change. Do not send email addresses. Must not be greater than 100 characters.' example: Anna nullable: true required: - group_id - type /api/v2/monitoring/trigger/extend: post: summary: 'Extend Monitoring Trigger' operationId: extendMonitoringTrigger description: "Reports pages of a monitoring `Group` that are still being edited without being saved, e.g. a\nWordPress autosave. For each page that already waits for its trigger check, the wait is restarted\n(7 minutes from now), so the check runs only once the editing has stopped.\n\nAn extension never starts a check: pages without a waiting check are listed under `ignored`\n(`not_waiting`) and nothing happens for them. Extensions do not count towards the hourly cap of\nthe trigger endpoint and cost nothing. The Group must be an enabled monitoring Group with the\ntrigger `type` in its `triggers`." parameters: [] responses: 202: description: '' content: application/json: schema: type: object example: data: group_id: 023c282c-6513-420a-a36b-a654312ab229 type: post_save accepted: - example.com/about ignored: - url: 'https://example.com/contact/' reason: not_waiting run_at: '2026-09-25T10:07:00.000000Z' properties: data: type: object properties: group_id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 type: type: string example: post_save accepted: type: array example: - example.com/about items: type: string ignored: type: array example: - url: 'https://example.com/contact/' reason: not_waiting items: type: object properties: url: type: string example: 'https://example.com/contact/' reason: type: string example: not_waiting run_at: type: string example: '2026-09-25T10:07:00.000000Z' tags: - 'Monitoring Trigger' requestBody: required: true content: application/json: schema: type: object properties: group_id: type: string description: 'ID of the monitoring Group the URLs belong to. The Group must have the trigger `type` in its `triggers`. Must not be greater than 36 characters.' example: 023c282c-6513-420a-a36b-a654312ab229 type: type: string description: 'The trigger type of the waiting check. Allowed values: `post_save`.' example: post_save enum: - post_save urls: type: array description: 'The pages that are still being edited, max. 50 per request. Only pages with a waiting check are extended; others are returned under `ignored`.' example: - url: 'https://example.com/about/' items: type: object properties: url: type: string description: 'The page URL, with or without protocol and trailing slash. Must not be greater than 2048 characters.' example: 'https://example.com/about/' required: - url required: - group_id - type - urls /api/v2/monitoring/running: get: summary: 'Get Running Monitoring' operationId: getRunningMonitoring description: "Tells for each requested monitoring `Group` whether a monitoring run is in progress, and which\none. Counts every monitoring run of the Group: scheduled, trigger-based and manual\n(`manual_trigger`), including its comparisons.\n\nEvery requested Group that is one of your monitoring Groups is listed, with `batch_id` = the\nrunning Batch or `null` when nothing runs. Unknown Groups, Groups of other accounts and manual\nGroups are left out (no 404); treat a missing Group as not running. With several running\nBatches the newest one is returned. Checks open or processing for more than 60 minutes are\nconsidered stuck and do not count.\n\nWhether the run is finished, and its result, comes from `GET /batches/{id}`: the Batch is\nfinished when `finished_at` is set, which can be a few minutes after the Group stopped running." parameters: - in: query name: group_ids description: 'Comma separated list of monitoring Group IDs, max. 50.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' required: true schema: type: string description: 'Comma separated list of monitoring Group IDs, max. 50.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' responses: 200: description: '' content: application/json: schema: type: object example: data: - group_id: 023c282c-6513-420a-a36b-a654312ab229 batch_id: 0d5f8108-51f1-4961-939a-2d33c7145918 - group_id: 023c282c-6513-420a-a36b-a654312ab230 batch_id: null properties: data: type: array example: - group_id: 023c282c-6513-420a-a36b-a654312ab229 batch_id: 0d5f8108-51f1-4961-939a-2d33c7145918 - group_id: 023c282c-6513-420a-a36b-a654312ab230 batch_id: null items: type: object properties: group_id: type: string example: 023c282c-6513-420a-a36b-a654312ab229 batch_id: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 tags: - 'Monitoring Trigger' /api/v2/queues: get: summary: 'List Queues' operationId: listQueues description: "Returns a list of all `Queues`. The `Queues` are sorted by creation date, with the most recent `Queues` appearing first.\n\nWhen filtering by `batch` or `batches` parameter, the response includes additional metadata:\n- `meta.status_counts`: Aggregated status counts across all filtered batches\n- `meta.status_counts.by_type`: Status counts grouped by screenshot type (pre, post, comparison)\n- `meta.status_counts_by_batch`: Status counts for each individual batch, including a per-batch `by_type` breakdown" parameters: - in: query name: status description: 'Comma separated list of status to filter for.' example: 'done,failed' required: false schema: type: string description: 'Comma separated list of status to filter for.' example: 'done,failed' - in: query name: groups description: 'Comma separated list of Group UUIDs to filter for.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' required: false schema: type: string description: 'Comma separated list of Group UUIDs to filter for.' example: '023c282c-6513-420a-a36b-a654312ab229,023c282c-6513-420a-a36b-a654312ab230' - in: query name: batches description: 'Comma separated list of Batch UUIDs to filter for.' example: '0d5f8108-51f1-4961-939a-2d33c7145918,1d5f8108-51f1-4961-939a-2d33c7145918' required: false schema: type: string description: 'Comma separated list of Batch UUIDs to filter for.' example: '0d5f8108-51f1-4961-939a-2d33c7145918,1d5f8108-51f1-4961-939a-2d33c7145918' responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 3bf0cec1-e8ee-49ba-804e-0db5ed93a7e3 url: 418e0748-a9cf-480b-86d6-88b00bac00b9 batch: 0d5f8108-51f1-4961-939a-2d33c7145918 group: 023c282c-6513-420a-a36b-a654312ab229 device: desktop status: open error_msg: null sc_type: pre css: null js: null monitoring: true url_link: 'https://example.com' html_title: 'Example Title' image_link: 'https://images.webchangedetector.com/image.jpg' created_at: '2024-08-08 13:37:42' updated_at: '2024-08-08 13:37:42' links: first: 'http://api.webchangedetector.test/api/v2/queues?page=1' last: 'http://api.webchangedetector.test/api/v2/queues?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/queues?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/queues' per_page: 15 to: 1 total: 1 status_counts: open: 15 processing: 3 done: 42 failed: 2 by_type: pre: open: 5 processing: 1 done: 14 failed: 0 post: open: 5 processing: 1 done: 14 failed: 1 comparison: open: 5 processing: 1 done: 14 failed: 1 status_counts_by_batch: 0d5f8108-51f1-4961-939a-2d33c7145918: open: 10 processing: 2 done: 30 failed: 1 by_type: pre: open: 0 processing: 0 done: 15 failed: 0 post: open: 10 processing: 2 done: 3 failed: 0 compare: open: 0 processing: 0 done: 12 failed: 1 properties: data: type: array example: - id: 3bf0cec1-e8ee-49ba-804e-0db5ed93a7e3 url: 418e0748-a9cf-480b-86d6-88b00bac00b9 batch: 0d5f8108-51f1-4961-939a-2d33c7145918 group: 023c282c-6513-420a-a36b-a654312ab229 device: desktop status: open error_msg: null sc_type: pre css: null js: null monitoring: true url_link: 'https://example.com' html_title: 'Example Title' image_link: 'https://images.webchangedetector.com/image.jpg' created_at: '2024-08-08 13:37:42' updated_at: '2024-08-08 13:37:42' items: type: object properties: id: type: string example: 3bf0cec1-e8ee-49ba-804e-0db5ed93a7e3 url: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 device: type: string example: desktop status: type: string example: open error_msg: type: string example: null nullable: true sc_type: type: string example: pre css: type: string example: null nullable: true js: type: string example: null nullable: true monitoring: type: boolean example: true url_link: type: string example: 'https://example.com' html_title: type: string example: 'Example Title' image_link: type: string example: 'https://images.webchangedetector.com/image.jpg' created_at: type: string example: '2024-08-08 13:37:42' updated_at: type: string example: '2024-08-08 13:37:42' links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/queues?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/queues?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/queues?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/queues' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 status_counts: type: object properties: open: type: integer example: 15 processing: type: integer example: 3 done: type: integer example: 42 failed: type: integer example: 2 by_type: type: object properties: pre: type: object properties: open: type: integer example: 5 processing: type: integer example: 1 done: type: integer example: 14 failed: type: integer example: 0 post: type: object properties: open: type: integer example: 5 processing: type: integer example: 1 done: type: integer example: 14 failed: type: integer example: 1 comparison: type: object properties: open: type: integer example: 5 processing: type: integer example: 1 done: type: integer example: 14 failed: type: integer example: 1 status_counts_by_batch: type: object properties: 0d5f8108-51f1-4961-939a-2d33c7145918: type: object properties: open: type: integer example: 10 processing: type: integer example: 2 done: type: integer example: 30 failed: type: integer example: 1 by_type: type: object properties: pre: type: object properties: open: { type: integer, example: 0 } processing: { type: integer, example: 0 } done: { type: integer, example: 15 } failed: { type: integer, example: 0 } post: type: object properties: open: { type: integer, example: 10 } processing: { type: integer, example: 2 } done: { type: integer, example: 3 } failed: { type: integer, example: 0 } compare: type: object properties: open: { type: integer, example: 0 } processing: { type: integer, example: 0 } done: { type: integer, example: 12 } failed: { type: integer, example: 1 } tags: - Queue '/api/v2/queues/{id}': get: summary: 'Get Queue' operationId: getQueue description: 'Retrieves a `Queue` object identfied by their ID' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 3bf0cec1-e8ee-49ba-804e-0db5ed93a7e3 url: 418e0748-a9cf-480b-86d6-88b00bac00b9 batch: 0d5f8108-51f1-4961-939a-2d33c7145918 group: 023c282c-6513-420a-a36b-a654312ab229 device: desktop status: open sc_type: pre css: null js: null monitoring: true url_link: 'https://example.com' html_title: 'Example Title' image_link: 'https://images.webchangedetector.com/image.jpg' created_at: '2024-08-08 13:37:42' updated_at: '2024-08-08 13:37:42' properties: data: type: object properties: id: type: string example: 3bf0cec1-e8ee-49ba-804e-0db5ed93a7e3 url: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 device: type: string example: desktop status: type: string example: open sc_type: type: string example: pre css: type: string example: null nullable: true js: type: string example: null nullable: true monitoring: type: boolean example: true url_link: type: string example: 'https://example.com' html_title: type: string example: 'Example Title' image_link: type: string example: 'https://images.webchangedetector.com/image.jpg' created_at: type: string example: '2024-08-08 13:37:42' updated_at: type: string example: '2024-08-08 13:37:42' tags: - Queue parameters: - in: path name: id description: 'The ID of the Queue.' example: 3bf0cec1-e8ee-49ba-804e-0db5ed93a7e3 required: true schema: type: string /api/v2/screenshots: get: summary: 'List Screenshots' operationId: listScreenshots description: "Returns a list of all `Screenshots`. The `Screenshots` are sorted by creation date, with\nthe most recent `Screenshots` appearing first." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 domain: example.com url: example.com/foobar link: 'https://images.webchangedetector.com/example.jpg' device: desktop sc_type: pre monitoring: true browser_console: text: 'Failed to load resource: the server responded with a status of 404 ()' type: error location: url: 'https://example.com.com/favicon.ico' links: first: 'http://api.webchangedetector.test/api/v2/screenshots?page=1' last: 'http://api.webchangedetector.test/api/v2/screenshots?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/screenshots?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/screenshots' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 domain: example.com url: example.com/foobar link: 'https://images.webchangedetector.com/example.jpg' device: desktop sc_type: pre monitoring: true browser_console: text: 'Failed to load resource: the server responded with a status of 404 ()' type: error location: url: 'https://example.com.com/favicon.ico' items: type: object properties: id: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae queue: type: string example: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 domain: type: string example: example.com url: type: string example: example.com/foobar link: type: string example: 'https://images.webchangedetector.com/example.jpg' device: type: string example: desktop sc_type: type: string example: pre monitoring: type: boolean example: true browser_console: type: object properties: text: type: string example: 'Failed to load resource: the server responded with a status of 404 ()' type: type: string example: error location: type: object properties: url: type: string example: 'https://example.com.com/favicon.ico' links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/screenshots?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/screenshots?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/screenshots?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/screenshots' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Screenshot '/api/v2/screenshots/{id}': get: summary: 'Get Screenshot' operationId: getScreenshot description: 'Retrieves a `Screenshot` object identfied by their ID' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae queue: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 domain: example.com url: example.com/foobar link: 'https://images.webchangedetector.com/example.jpg' device: desktop sc_type: pre monitoring: true browser_console: text: 'Failed to load resource: the server responded with a status of 404 ()' type: error location: url: 'https://example.com.com/favicon.ico' properties: data: type: object properties: id: type: string example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae queue: type: string example: 8ea7b88d-b5c6-4fad-8e9d-1497a54d9266 domain: type: string example: example.com url: type: string example: example.com/foobar link: type: string example: 'https://images.webchangedetector.com/example.jpg' device: type: string example: desktop sc_type: type: string example: pre monitoring: type: boolean example: true browser_console: type: object properties: text: type: string example: 'Failed to load resource: the server responded with a status of 404 ()' type: type: string example: error location: type: object properties: url: type: string example: 'https://example.com.com/favicon.ico' tags: - Screenshot parameters: - in: path name: id description: 'The ID of the Screenshot.' example: 958dce2c-8468-47d3-8bc2-7dc6bf0aadae required: true schema: type: string /api/v2/screenshots/take: post: summary: 'Take Screenshot' operationId: takeScreenshot description: "Adds screenshots of URLs in the passed groups to the queue. The parameter sc_type indicates if\npre-update screenshots are taken (pre) or post-update screenshots and comparisons are taken (post).\nWhen post-update screenshots are done, a comparison is automatically triggered.\n\nBy default all groups share ONE batch. With `batch_per_group=true` each group gets its own batch\nand the response additionally contains a `batches` map (group UUID => batch UUID)." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: Success type: object example: batch: 0d5f8108-51f1-4961-939a-2d33c7145918 amount_screenshots: 42 groups: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 properties: batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 amount_screenshots: type: integer example: 42 groups: type: array example: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 items: type: string - description: 'Success (batch_per_group=true)' type: object example: batch: 0d5f8108-51f1-4961-939a-2d33c7145918 amount_screenshots: 42 groups: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 batches: 023c282c-6513-420a-a36b-a654312ab229: 0d5f8108-51f1-4961-939a-2d33c7145918 023c282c-6513-420a-a36b-a654312ab230: 1e6f9219-62f2-5a72-a4ab-3e44d8256a29 properties: batch: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 amount_screenshots: type: integer example: 42 groups: type: array example: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 items: type: string batches: type: object properties: 023c282c-6513-420a-a36b-a654312ab229: type: string example: 0d5f8108-51f1-4961-939a-2d33c7145918 023c282c-6513-420a-a36b-a654312ab230: type: string example: 1e6f9219-62f2-5a72-a4ab-3e44d8256a29 402: description: 'Not enough credits' content: application/json: schema: type: object example: message: 'Bummer, you used your credit already. Please upgrade your account to a bigger plan.' properties: message: type: string example: 'Bummer, you used your credit already. Please upgrade your account to a bigger plan.' 422: description: 'All selected URLs are unsupported content (batch_per_group=true)' content: application/json: schema: type: object example: message: 'None of the selected URLs can be checked. Only HTML pages are supported (not PDFs, images, or other files).' properties: message: type: string example: 'None of the selected URLs can be checked. Only HTML pages are supported (not PDFs, images, or other files).' tags: - Screenshot requestBody: required: true content: application/json: schema: type: object properties: group_ids: type: array description: 'A list of Groups.' example: '["023c282c-6513-420a-a36b-a654312ab229", "023c282c-6513-420a-a36b-a654312ab230"]' items: type: string sc_type: type: string description: 'Screenshot phase. `pre` captures the baseline before changes; `post` captures after changes and triggers comparisons against the matching `pre` screenshots in the same Batch.' example: pre enum: - pre - post source: type: string description: 'Optional batch source tag for filtering / reporting. Allowed values: see `Batch::SOURCE_ALL` (e.g. `manual`, `auto_update`, `monitoring`).' example: manual enum: - manual - monitoring - auto_update batch_per_group: type: boolean description: 'When `true`, one Batch is created PER group instead of a single shared batch. The response then additionally contains a `batches` object mapping each started group UUID to its batch UUID; groups that could not be started (no credits, nothing to check) are omitted from the map. Defaults to `false` (unchanged single-batch behavior and response). Send as JSON boolean or `0`/`1` — the strings `"true"`/`"false"` are rejected with 422.' example: false required: - group_ids /api/v2/invitations/verify: post: summary: 'Verify Invitation' operationId: verifyInvitation description: "Returns subaccount details for a valid invitation token, including the decrypted API token.\nIdempotent: can be called multiple times until the invitation is accepted or expires.\nDoes NOT consume the token. Use POST /invitations/accept after the user has finished\nsetting up their account to mark the invitation as consumed.\nThis endpoint does not require authentication." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: Jane name_last: Doe email: mail@example.com api_token: V82abQfqPA3hBXL9ZHfMAt94Ta23VUdYt691D7GO properties: data: type: object properties: id: type: string example: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: type: string example: Jane name_last: type: string example: Doe email: type: string example: mail@example.com api_token: type: string example: V82abQfqPA3hBXL9ZHfMAt94Ta23VUdYt691D7GO tags: - Subaccount requestBody: required: true content: application/json: schema: type: object properties: invitation_token: type: string description: 'The invitation token from the email' example: ducimus required: - invitation_token /api/v2/invitations/accept: post: summary: 'Accept Invitation' operationId: acceptInvitation description: "Marks a subaccount invitation as accepted, consuming the token. Should be called by the\nwebapp AFTER the local user account has been successfully created — calling this before\nis a self-DoS because the token is cleared and cannot be re-verified afterwards.\nThis endpoint does not require authentication." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Invitation accepted' properties: message: type: string example: 'Invitation accepted' tags: - Subaccount requestBody: required: true content: application/json: schema: type: object properties: invitation_token: type: string description: 'The invitation token from the email' example: reprehenderit required: - invitation_token /api/v2/subaccounts: get: summary: 'List Subaccounts' operationId: listSubaccounts description: "Returns a list of all `Subaccounts`. The `Subaccounts` are sorted by creation date, with\nthe most recent `Subaccounts` appearing first." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: Jane name_last: Doe email: mail@example.com checks_done: 42 checks_left: 1337 timezone: UTC is_subaccount: true links: first: 'http://api.webchangedetector.test/api/v2/subaccounts?page=1' last: 'http://api.webchangedetector.test/api/v2/subaccounts?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/subaccounts?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/subaccounts' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: Jane name_last: Doe email: mail@example.com checks_done: 42 checks_left: 1337 timezone: UTC is_subaccount: true items: type: object properties: id: type: string example: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: type: string example: Jane name_last: type: string example: Doe email: type: string example: mail@example.com checks_done: type: integer example: 42 checks_left: type: integer example: 1337 timezone: type: string example: UTC is_subaccount: type: boolean example: true links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/subaccounts?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/subaccounts?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/subaccounts?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/subaccounts' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Subaccount post: summary: 'Create Subaccount' operationId: createSubaccount description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: Jane name_last: Doe email: mail@example.com checks_done: 42 checks_left: 1337 timezone: UTC api_token: V82abQfqPA3hBXL9ZHfMAt94Ta23VUdYt691D7GO is_subaccount: true properties: data: type: object properties: id: type: string example: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: type: string example: Jane name_last: type: string example: Doe email: type: string example: mail@example.com checks_done: type: integer example: 42 checks_left: type: integer example: 1337 timezone: type: string example: UTC api_token: type: string example: V82abQfqPA3hBXL9ZHfMAt94Ta23VUdYt691D7GO is_subaccount: type: boolean example: true tags: - Subaccount requestBody: required: true content: application/json: schema: type: object properties: name_first: type: string description: 'First Name' example: Hans name_last: type: string description: 'Last Name' example: Hacker email: type: string description: 'Must be a valid email' example: mail@example.com limit_checks: type: number description: "Maximum number of checks per renewal period this subaccount may consume. Capped at the parent account's plan limit (not remaining quota). Must be at least 0." example: 1000.0 plan_label: type: string description: 'Optional display label shown in the subaccount UI (e.g. "Agency Starter"). No billing semantics — purely cosmetic. Must not be greater than 255 characters.' example: 'Agency Starter' nullable: true can_create_subaccounts: type: boolean description: 'Allow this subaccount to itself manage subaccounts (level-1 reseller). Defaults to `false`.' example: false required: - name_first - name_last - email - limit_checks '/api/v2/subaccounts/{id}': get: summary: 'Get Subaccount' operationId: getSubaccount description: 'Retrieves a `Subaccount` object identfied by their ID' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: Jane name_last: Doe email: mail@example.com checks_done: 42 checks_left: 1337 timezone: UTC is_subaccount: true properties: data: type: object properties: id: type: string example: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: type: string example: Jane name_last: type: string example: Doe email: type: string example: mail@example.com checks_done: type: integer example: 42 checks_left: type: integer example: 1337 timezone: type: string example: UTC is_subaccount: type: boolean example: true tags: - Subaccount put: summary: 'Update Subaccount' operationId: updateSubaccount description: "Updates the specified `Subaccount` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: Jane name_last: Doe email: mail@example.com checks_done: 42 checks_left: 1337 timezone: UTC is_subaccount: true properties: data: type: object properties: id: type: string example: 17482316-2398-4374-9f70-e0e3e2bf292a name_first: type: string example: Jane name_last: type: string example: Doe email: type: string example: mail@example.com checks_done: type: integer example: 42 checks_left: type: integer example: 1337 timezone: type: string example: UTC is_subaccount: type: boolean example: true tags: - Subaccount requestBody: required: true content: application/json: schema: type: object properties: name_first: type: string description: 'First Name' example: Hans name_last: type: string description: 'Last Name' example: Hacker limit_checks: type: number description: "New per-renewal-period check quota. Capped at the parent account's plan limit. Email is immutable on update. Must be at least 0." example: 1500.0 plan_label: type: string description: 'Optional display label shown in the subaccount UI. No billing semantics. Must not be greater than 255 characters.' example: 'Agency Pro' nullable: true can_create_subaccounts: type: boolean description: 'Toggle subaccount-management permission for this user.' example: false required: - name_first - name_last delete: summary: 'Delete Subaccount' operationId: deleteSubaccount description: "Permanently deletes a `Subaccount`. This cannot be undone.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Subaccount deleted' properties: message: type: string example: 'Subaccount deleted' tags: - Subaccount parameters: - in: path name: id description: 'The ID of the Subaccount.' example: 17482316-2398-4374-9f70-e0e3e2bf292a required: true schema: type: string '/api/v2/subaccounts/{id}/invite': post: summary: 'Invite Subaccount' operationId: inviteSubaccount description: "Sends an invitation email to a `Subaccount` user, allowing them to create their own webapp login.\nWorks for both new and existing subaccounts." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Invitation sent' properties: message: type: string example: 'Invitation sent' tags: - Subaccount parameters: - in: path name: id description: 'The UUID of the Subaccount.' example: 17482316-2398-4374-9f70-e0e3e2bf292a required: true schema: type: string /api/v2/urls: get: summary: 'List Urls' operationId: listUrls description: "Returns a list of all `Urls`. The `Urls` are sorted by creation date, with\nthe most recent `Urls` appearing first." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' type: types category: Seiten website: 91e9c9fd-b86f-4269-a3f4-f02810167a6d groups: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 status_code: 200 error_count: 0 links: first: 'http://api.webchangedetector.test/api/v2/urls?page=1' last: 'http://api.webchangedetector.test/api/v2/urls?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/urls?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/urls' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' type: types category: Seiten website: 91e9c9fd-b86f-4269-a3f4-f02810167a6d groups: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 status_code: 200 error_count: 0 items: type: object properties: id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: type: string example: 'Example Title' url: type: string example: example.com/foobar last_crawled_at: type: string example: '2025-01-01 13:37:42' type: type: string example: types category: type: string example: Seiten website: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d groups: type: array example: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 items: type: string status_code: type: integer example: 200 error_count: type: integer example: 0 links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/urls?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/urls?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/urls?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/urls' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Url post: summary: 'Create Url' operationId: createUrl description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' type: null category: null website: null groups: [] status_code: 200 error_count: 0 properties: data: type: object properties: id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: type: string example: 'Example Title' url: type: string example: example.com/foobar last_crawled_at: type: string example: '2025-01-01 13:37:42' type: type: string example: null nullable: true category: type: string example: null nullable: true website: type: string example: null nullable: true groups: type: array example: [] status_code: type: integer example: 200 error_count: type: integer example: 0 tags: - Url requestBody: required: true content: application/json: schema: type: object properties: url: type: string description: 'Must be a valid URL' example: 'https://example.com' required: - url '/api/v2/urls/{id}': get: summary: 'Get Url' operationId: getUrl description: 'Retrieves a `Url` object identfied by their ID' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' type: types category: Seiten website: 91e9c9fd-b86f-4269-a3f4-f02810167a6d groups: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 status_code: 200 error_count: 0 properties: data: type: object properties: id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: type: string example: 'Example Title' url: type: string example: example.com/foobar last_crawled_at: type: string example: '2025-01-01 13:37:42' type: type: string example: types category: type: string example: Seiten website: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d groups: type: array example: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 items: type: string status_code: type: integer example: 200 error_count: type: integer example: 0 tags: - Url put: summary: 'Update Url' operationId: updateUrl description: "Updates the specified `Url` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: 'Example Title' url: example.com/foobar last_crawled_at: '2025-01-01 13:37:42' type: types category: Seiten website: 91e9c9fd-b86f-4269-a3f4-f02810167a6d status_code: 200 error_count: 0 groups: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 properties: data: type: object properties: id: type: string example: 418e0748-a9cf-480b-86d6-88b00bac00b9 html_title: type: string example: 'Example Title' url: type: string example: example.com/foobar last_crawled_at: type: string example: '2025-01-01 13:37:42' type: type: string example: types category: type: string example: Seiten website: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d status_code: type: integer example: 200 error_count: type: integer example: 0 groups: type: array example: - 023c282c-6513-420a-a36b-a654312ab229 - 023c282c-6513-420a-a36b-a654312ab230 items: type: string tags: - Url requestBody: required: true content: application/json: schema: type: object properties: url: type: string description: 'Must be a valid URL' example: 'https://example.com' required: - url delete: summary: 'Delete Url' operationId: deleteUrl description: "Permanently deletes a `Url`. This cannot be undone.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'URL deleted' properties: message: type: string example: 'URL deleted' tags: - Url parameters: - in: path name: id description: 'The ID of the Url.' example: 418e0748-a9cf-480b-86d6-88b00bac00b9 required: true schema: type: string /api/v2/urls/add-from-sitemap: post: summary: 'Add From Sitemap' operationId: addFromSitemap description: "Adds all the URLs found in a sitemap for a given domain.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Sitemap parsing started.' properties: message: type: string example: 'Sitemap parsing started.' tags: - Url requestBody: required: true content: application/json: schema: type: object properties: domain: type: string description: 'The domain to parse the sitemap from' example: example.com required: - domain /api/v2/webhooks: get: summary: 'List Webhooks' operationId: listWebhooks description: "Returns a list of all Webhooks. The Webhooks are sorted by creation date, with\nthe most recent Webhooks appearing first." parameters: - in: query name: event description: 'Event of the Queue.' example: comparison_status_new required: false schema: type: string description: 'Event of the Queue.' example: comparison_status_new enum: - batch_finished - comparison_status_new - queue_status_done - queue_status_failed responses: 200: description: '' content: application/json: schema: type: object example: data: - id: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: comparison_status_new url: 'https://example.com' links: first: 'http://api.webchangedetector.test/api/v2/webhooks?page=1' last: 'http://api.webchangedetector.test/api/v2/webhooks?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/webhooks?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/webhooks' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: comparison_status_new url: 'https://example.com' items: type: object properties: id: type: string example: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: type: string example: comparison_status_new url: type: string example: 'https://example.com' links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/webhooks?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/webhooks?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/webhooks?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/webhooks' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Webhook post: summary: 'Create Webhook' operationId: createWebhook description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: comparison_status_new url: 'https://example.com' properties: data: type: object properties: id: type: string example: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: type: string example: comparison_status_new url: type: string example: 'https://example.com' tags: - Webhook requestBody: required: true content: application/json: schema: type: object properties: url: type: string description: 'HTTPS endpoint that receives the webhook POST. Requests are signed with HMAC-SHA256 in the `Signature` header — verify against your account webhook secret (GET /api/v2/account). Must be a valid URL.' example: 'https://example.com/webhooks/wcd' event: type: string description: 'Event to subscribe to. Allowed values for the v2 API: `batch_finished` (all Screenshots in a Batch complete; the payload carries the Batch `source` and `trigger_context`, see List Batches), `comparison_status_new` (a change was detected), `queue_status_done`, `queue_status_failed`. See `Webhook::EVENTS_ALL_API_V2`.' example: batch_finished enum: - batch_finished - comparison_status_new - comparison_status_new_collection - comparison_summary - queue_status_done - queue_status_failed - wordpress_cron - wordpress_single_call required: - url - event '/api/v2/webhooks/{id}': get: summary: 'Get Webhook' operationId: getWebhook description: 'Retrieves a Webhook object identfied by their ID' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: comparison_status_new url: 'https://example.com' properties: data: type: object properties: id: type: string example: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: type: string example: comparison_status_new url: type: string example: 'https://example.com' tags: - Webhook put: summary: 'Update Webhook' operationId: updateWebhook description: "Updates the specified `Webhook` by setting the values of the parameters passed.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: comparison_status_new url: 'https://example.com' properties: data: type: object properties: id: type: string example: d86e9245-3524-4f8d-b5d9-e4a472136d27 event: type: string example: comparison_status_new url: type: string example: 'https://example.com' tags: - Webhook requestBody: required: true content: application/json: schema: type: object properties: url: type: string description: 'Must be a valid URL' example: 'https://example.com' required: - url delete: summary: 'Delete Webhook' operationId: deleteWebhook description: 'Permanently deletes a `Webhook`. This cannot be undone.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: '{ID} deleted' properties: message: type: string example: '{ID} deleted' tags: - Webhook parameters: - in: path name: id description: 'The ID of the Webhook.' example: d86e9245-3524-4f8d-b5d9-e4a472136d27 required: true schema: type: string /api/v2/websites: get: summary: 'List Websites' operationId: listWebsites description: "Returns a list of all `Website`. The `Websites` are sorted by creation date, with\nthe most recent `Websites` appearing first.\n" parameters: - in: query name: domain description: 'Filter websites by domain. Must not be greater than 253 characters.' example: example.com required: false schema: type: string description: 'Filter websites by domain. Must not be greater than 253 characters.' example: example.com nullable: true - in: query name: managed_by description: 'Filter websites by owning integration (e.g. native, mainwp). Omit for all.' example: mainwp required: false schema: type: string description: 'Filter websites by owning integration (e.g. native, mainwp). Omit for all.' example: mainwp enum: - native - mainwp nullable: true responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 91e9c9fd-b86f-4269-a3f4-f02810167a6d manual_detection_group: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: 023c282c-6513-420a-a36b-a654312ab230 domain: example.com last_seen_at: '2025-07-14T16:19:30Z' plugin_version: 4.0.3 is_multisite_subsite: false parent_multisite_website: null sync_url_types: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts auto_update_settings: auto_update_checks_enabled: false auto_update_checks_from: '13:37' auto_update_checks_to: '13:42' auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_emails: mail@example.com allow_core_security_updates: true allowances: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true links: first: 'http://api.webchangedetector.test/api/v2/websites?page=1' last: 'http://api.webchangedetector.test/api/v2/websites?page=1' prev: null next: null meta: current_page: 1 from: 1 last_page: 1 links: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/websites?page=1' label: '1' active: true - url: null label: 'Next »' active: false path: 'http://api.webchangedetector.test/api/v2/websites' per_page: 15 to: 1 total: 1 properties: data: type: array example: - id: 91e9c9fd-b86f-4269-a3f4-f02810167a6d manual_detection_group: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: 023c282c-6513-420a-a36b-a654312ab230 domain: example.com last_seen_at: '2025-07-14T16:19:30Z' plugin_version: 4.0.3 is_multisite_subsite: false parent_multisite_website: null sync_url_types: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts auto_update_settings: auto_update_checks_enabled: false auto_update_checks_from: '13:37' auto_update_checks_to: '13:42' auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_emails: mail@example.com allow_core_security_updates: true allowances: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true items: type: object properties: id: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d manual_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab230 domain: type: string example: example.com last_seen_at: type: string example: '2025-07-14T16:19:30Z' plugin_version: type: string example: 4.0.3 is_multisite_subsite: type: boolean example: false parent_multisite_website: type: string example: null nullable: true sync_url_types: type: array example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts items: type: object properties: url_type_slug: type: string example: types url_type_name: type: string example: 'Post Types' post_type_slug: type: string example: posts post_type_name: type: string example: Posts auto_update_settings: type: object properties: auto_update_checks_enabled: type: boolean example: false auto_update_checks_from: type: string example: '13:37' auto_update_checks_to: type: string example: '13:42' auto_update_checks_monday: type: boolean example: true auto_update_checks_tuesday: type: boolean example: true auto_update_checks_wednesday: type: boolean example: true auto_update_checks_thursday: type: boolean example: true auto_update_checks_friday: type: boolean example: true auto_update_checks_saturday: type: boolean example: false auto_update_checks_sunday: type: boolean example: false auto_update_checks_emails: type: string example: mail@example.com allow_core_security_updates: type: boolean example: true allowances: type: object properties: change_detections_view: type: boolean example: true ai_rules_view: type: boolean example: true manual_checks_view: type: boolean example: true manual_checks_start: type: boolean example: true manual_checks_settings: type: boolean example: true manual_checks_urls: type: boolean example: true monitoring_checks_view: type: boolean example: true monitoring_checks_settings: type: boolean example: true monitoring_checks_urls: type: boolean example: true logs_view: type: boolean example: true settings_view: type: boolean example: true settings_add_urls: type: boolean example: true settings_account_settings: type: boolean example: true upgrade_account: type: boolean example: true wizard_start: type: boolean example: true only_frontpage: type: boolean example: false plugin_view: type: boolean example: true links: type: object properties: first: type: string example: 'http://api.webchangedetector.test/api/v2/websites?page=1' last: type: string example: 'http://api.webchangedetector.test/api/v2/websites?page=1' prev: type: string example: null nullable: true next: type: string example: null nullable: true meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 1 links: type: array example: - url: null label: '« Previous' active: false - url: 'http://api.webchangedetector.test/api/v2/websites?page=1' label: '1' active: true - url: null label: 'Next »' active: false items: type: object properties: url: type: string example: null nullable: true label: type: string example: '« Previous' active: type: boolean example: false path: type: string example: 'http://api.webchangedetector.test/api/v2/websites' per_page: type: integer example: 15 to: type: integer example: 1 total: type: integer example: 1 tags: - Website post: summary: 'Create Website' operationId: createWebsite description: "Creates a `Website` by setting the values of the parameters passed.\nTypically only done by the WordPress plugin.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 91e9c9fd-b86f-4269-a3f4-f02810167a6d domain: example.com last_seen_at: '2025-07-14T16:19:30Z' plugin_version: 4.0.3 manual_detection_group: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: 023c282c-6513-420a-a36b-a654312ab230 is_multisite_subsite: false parent_multisite_website: null allowances: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true sync_url_types: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts - url_type_slug: types url_type_name: 'Post Types' post_type_slug: pages post_type_name: Pages - url_type_slug: taxonomies url_type_name: Taxonomies post_type_slug: category post_type_name: Category auto_update_settings: auto_update_checks_enabled: false auto_update_checks_from: '13:37' auto_update_checks_to: '13:42' auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_emails: mail@example.com allow_core_security_updates: true properties: id: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d domain: type: string example: example.com last_seen_at: type: string example: '2025-07-14T16:19:30Z' plugin_version: type: string example: 4.0.3 manual_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab230 is_multisite_subsite: type: boolean example: false parent_multisite_website: type: string example: null nullable: true allowances: type: object properties: change_detections_view: type: boolean example: true ai_rules_view: type: boolean example: true manual_checks_view: type: boolean example: true manual_checks_start: type: boolean example: true manual_checks_settings: type: boolean example: true manual_checks_urls: type: boolean example: true monitoring_checks_view: type: boolean example: true monitoring_checks_settings: type: boolean example: true monitoring_checks_urls: type: boolean example: true logs_view: type: boolean example: true settings_view: type: boolean example: true settings_add_urls: type: boolean example: true settings_account_settings: type: boolean example: true upgrade_account: type: boolean example: true wizard_start: type: boolean example: true only_frontpage: type: boolean example: false plugin_view: type: boolean example: true sync_url_types: type: array example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts - url_type_slug: types url_type_name: 'Post Types' post_type_slug: pages post_type_name: Pages - url_type_slug: taxonomies url_type_name: Taxonomies post_type_slug: category post_type_name: Category items: type: object properties: url_type_slug: type: string example: types url_type_name: type: string example: 'Post Types' post_type_slug: type: string example: posts post_type_name: type: string example: Posts auto_update_settings: type: object properties: auto_update_checks_enabled: type: boolean example: false auto_update_checks_from: type: string example: '13:37' auto_update_checks_to: type: string example: '13:42' auto_update_checks_monday: type: boolean example: true auto_update_checks_tuesday: type: boolean example: true auto_update_checks_wednesday: type: boolean example: true auto_update_checks_thursday: type: boolean example: true auto_update_checks_friday: type: boolean example: true auto_update_checks_saturday: type: boolean example: false auto_update_checks_sunday: type: boolean example: false auto_update_checks_emails: type: string example: mail@example.com allow_core_security_updates: type: boolean example: true tags: - Website requestBody: required: true content: application/json: schema: type: object properties: domain: type: string description: 'The domain of the Website.' example: example.com manual_detection_group_id: type: string description: 'The ID of the Manual Detection Group.' example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d auto_detection_group_id: type: string description: 'The ID of the Auto Detection Group.' example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d managed_by: type: string description: '' example: native enum: - native - mainwp nullable: true parent_multisite_website_id: type: string description: 'UUID of the multisite main Website if this Website is a subsite. Must belong to the same user and not itself be a subsite. Subsites inherit the Schedule from the main; only their own auto_update_checks_enabled takes effect.' example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d allowances: type: array description: 'The allowances of the Website.' example: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true items: type: string sync_url_types: type: array description: 'The sync url types of the Website.' example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts - url_type_slug: types url_type_name: 'Post Types' post_type_slug: pages post_type_name: Pages - url_type_slug: taxonomies url_type_name: Taxonomies post_type_slug: category post_type_name: Category items: type: string auto_update_settings: type: array description: 'The auto update settings of the Website.' example: auto_update_checks_enabled: false auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_from: null auto_update_checks_to: null auto_update_checks_emails: null allow_core_security_updates: true items: type: string required: - domain - manual_detection_group_id - auto_detection_group_id '/api/v2/websites/{id}': get: summary: 'Get Website' operationId: getWebsite description: "Retrieves a `Website` object identified by its ID.\n\nOn Multisite Subsites the returned `auto_update_settings` reflects the **effective (inherited)** values: Schedule fields (timeframe, weekdays, notification emails) come from the parent main Website, while `auto_update_checks_enabled` reflects this Subsite's own toggle. The `is_multisite_subsite` boolean and the nested `parent_multisite_website` object indicate the link.\n" parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: '' type: object example: data: id: 91e9c9fd-b86f-4269-a3f4-f02810167a6d manual_detection_group: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: 023c282c-6513-420a-a36b-a654312ab230 domain: example.com last_seen_at: '2025-07-14T16:19:30Z' plugin_version: 4.0.3 is_multisite_subsite: false parent_multisite_website: null sync_url_types: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts auto_update_settings: auto_update_checks_enabled: false auto_update_checks_from: '13:37' auto_update_checks_to: '13:42' auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_emails: mail@example.com allow_core_security_updates: true allowances: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true properties: data: type: object properties: id: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d manual_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab230 domain: type: string example: example.com last_seen_at: type: string example: '2025-07-14T16:19:30Z' plugin_version: type: string example: 4.0.3 is_multisite_subsite: type: boolean example: false parent_multisite_website: type: string example: null nullable: true sync_url_types: type: array example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts items: type: object properties: url_type_slug: type: string example: types url_type_name: type: string example: 'Post Types' post_type_slug: type: string example: posts post_type_name: type: string example: Posts auto_update_settings: type: object properties: auto_update_checks_enabled: type: boolean example: false auto_update_checks_from: type: string example: '13:37' auto_update_checks_to: type: string example: '13:42' auto_update_checks_monday: type: boolean example: true auto_update_checks_tuesday: type: boolean example: true auto_update_checks_wednesday: type: boolean example: true auto_update_checks_thursday: type: boolean example: true auto_update_checks_friday: type: boolean example: true auto_update_checks_saturday: type: boolean example: false auto_update_checks_sunday: type: boolean example: false auto_update_checks_emails: type: string example: mail@example.com allow_core_security_updates: type: boolean example: true allowances: type: object properties: change_detections_view: type: boolean example: true ai_rules_view: type: boolean example: true manual_checks_view: type: boolean example: true manual_checks_start: type: boolean example: true manual_checks_settings: type: boolean example: true manual_checks_urls: type: boolean example: true monitoring_checks_view: type: boolean example: true monitoring_checks_settings: type: boolean example: true monitoring_checks_urls: type: boolean example: true logs_view: type: boolean example: true settings_view: type: boolean example: true settings_add_urls: type: boolean example: true settings_account_settings: type: boolean example: true upgrade_account: type: boolean example: true wizard_start: type: boolean example: true only_frontpage: type: boolean example: false plugin_view: type: boolean example: true - description: 'Multisite Subsite (auto_update_settings reflect effective inherited values from the parent main Website)' type: object example: data: id: b3a9d2e5-2c64-4a16-8f1c-9e3b21f8a4e7 manual_detection_group: d4d2af0b-7a35-4b99-aa46-5c4f2bb9f1a1 auto_detection_group: d4d2af0b-7a35-4b99-aa46-5c4f2bb9f1a2 domain: shop.example.com last_seen_at: '2025-07-14T16:19:30Z' plugin_version: 4.0.3 is_multisite_subsite: true parent_multisite_website: id: 91e9c9fd-b86f-4269-a3f4-f02810167a6d domain: example.com sync_url_types: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts auto_update_settings: auto_update_checks_enabled: true auto_update_checks_from: '13:37' auto_update_checks_to: '13:42' auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_emails: mail@example.com allow_core_security_updates: true allowances: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true properties: data: type: object properties: id: type: string example: b3a9d2e5-2c64-4a16-8f1c-9e3b21f8a4e7 manual_detection_group: type: string example: d4d2af0b-7a35-4b99-aa46-5c4f2bb9f1a1 auto_detection_group: type: string example: d4d2af0b-7a35-4b99-aa46-5c4f2bb9f1a2 domain: type: string example: shop.example.com last_seen_at: type: string example: '2025-07-14T16:19:30Z' plugin_version: type: string example: 4.0.3 is_multisite_subsite: type: boolean example: true parent_multisite_website: type: object properties: id: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d domain: type: string example: example.com sync_url_types: type: array example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts items: type: object properties: url_type_slug: type: string example: types url_type_name: type: string example: 'Post Types' post_type_slug: type: string example: posts post_type_name: type: string example: Posts auto_update_settings: type: object properties: auto_update_checks_enabled: type: boolean example: true auto_update_checks_from: type: string example: '13:37' auto_update_checks_to: type: string example: '13:42' auto_update_checks_monday: type: boolean example: true auto_update_checks_tuesday: type: boolean example: true auto_update_checks_wednesday: type: boolean example: true auto_update_checks_thursday: type: boolean example: true auto_update_checks_friday: type: boolean example: true auto_update_checks_saturday: type: boolean example: false auto_update_checks_sunday: type: boolean example: false auto_update_checks_emails: type: string example: mail@example.com allow_core_security_updates: type: boolean example: true allowances: type: object properties: change_detections_view: type: boolean example: true ai_rules_view: type: boolean example: true manual_checks_view: type: boolean example: true manual_checks_start: type: boolean example: true manual_checks_settings: type: boolean example: true manual_checks_urls: type: boolean example: true monitoring_checks_view: type: boolean example: true monitoring_checks_settings: type: boolean example: true monitoring_checks_urls: type: boolean example: true logs_view: type: boolean example: true settings_view: type: boolean example: true settings_add_urls: type: boolean example: true settings_account_settings: type: boolean example: true upgrade_account: type: boolean example: true wizard_start: type: boolean example: true only_frontpage: type: boolean example: false plugin_view: type: boolean example: true tags: - Website put: summary: 'Update Website' operationId: updateWebsite description: "Updates the specified `Website` by setting the values of the parameters passed.\nAny parameters not provided will be left unchanged.\n" parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 91e9c9fd-b86f-4269-a3f4-f02810167a6d domain: example.com last_seen_at: '2025-07-14T16:19:30Z' plugin_version: 4.0.3 manual_detection_group: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: 023c282c-6513-420a-a36b-a654312ab230 is_multisite_subsite: false parent_multisite_website: null allowances: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true sync_url_types: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts - url_type_slug: types url_type_name: 'Post Types' post_type_slug: pages post_type_name: Pages auto_update_settings: auto_update_checks_enabled: false auto_update_checks_from: '13:37' auto_update_checks_to: '13:42' auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_emails: mail@example.com allow_core_security_updates: true properties: id: type: string example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d domain: type: string example: example.com last_seen_at: type: string example: '2025-07-14T16:19:30Z' plugin_version: type: string example: 4.0.3 manual_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab229 auto_detection_group: type: string example: 023c282c-6513-420a-a36b-a654312ab230 is_multisite_subsite: type: boolean example: false parent_multisite_website: type: string example: null nullable: true allowances: type: object properties: change_detections_view: type: boolean example: true ai_rules_view: type: boolean example: true manual_checks_view: type: boolean example: true manual_checks_start: type: boolean example: true manual_checks_settings: type: boolean example: true manual_checks_urls: type: boolean example: true monitoring_checks_view: type: boolean example: true monitoring_checks_settings: type: boolean example: true monitoring_checks_urls: type: boolean example: true logs_view: type: boolean example: true settings_view: type: boolean example: true settings_add_urls: type: boolean example: true settings_account_settings: type: boolean example: true upgrade_account: type: boolean example: true wizard_start: type: boolean example: true only_frontpage: type: boolean example: false plugin_view: type: boolean example: true sync_url_types: type: array example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts - url_type_slug: types url_type_name: 'Post Types' post_type_slug: pages post_type_name: Pages items: type: object properties: url_type_slug: type: string example: types url_type_name: type: string example: 'Post Types' post_type_slug: type: string example: posts post_type_name: type: string example: Posts auto_update_settings: type: object properties: auto_update_checks_enabled: type: boolean example: false auto_update_checks_from: type: string example: '13:37' auto_update_checks_to: type: string example: '13:42' auto_update_checks_monday: type: boolean example: true auto_update_checks_tuesday: type: boolean example: true auto_update_checks_wednesday: type: boolean example: true auto_update_checks_thursday: type: boolean example: true auto_update_checks_friday: type: boolean example: true auto_update_checks_saturday: type: boolean example: false auto_update_checks_sunday: type: boolean example: false auto_update_checks_emails: type: string example: mail@example.com allow_core_security_updates: type: boolean example: true tags: - Website requestBody: required: false content: application/json: schema: type: object properties: parent_multisite_website_id: type: string description: 'UUID of the multisite main Website. Pass null to detach. On subsites only auto_update_checks_enabled takes effect in auto_update_settings; Schedule fields are inherited from the main at read time.' example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d allowances: type: array description: 'The allowances of the Website.' example: change_detections_view: true ai_rules_view: true manual_checks_view: true manual_checks_start: true manual_checks_settings: true manual_checks_urls: true monitoring_checks_view: true monitoring_checks_settings: true monitoring_checks_urls: true logs_view: true settings_view: true settings_add_urls: true settings_account_settings: true upgrade_account: true wizard_start: true only_frontpage: false plugin_view: true items: type: string sync_url_types: type: array description: 'The sync url types of the Website.' example: - url_type_slug: types url_type_name: 'Post Types' post_type_slug: posts post_type_name: Posts - url_type_slug: types url_type_name: 'Post Types' post_type_slug: pages post_type_name: Pages - url_type_slug: taxonomies url_type_name: Taxonomies post_type_slug: category post_type_name: Category items: type: string auto_update_settings: type: array description: 'The auto update settings of the Website.' example: auto_update_checks_enabled: false auto_update_checks_monday: true auto_update_checks_tuesday: true auto_update_checks_wednesday: true auto_update_checks_thursday: true auto_update_checks_friday: true auto_update_checks_saturday: false auto_update_checks_sunday: false auto_update_checks_from: null auto_update_checks_to: null auto_update_checks_emails: null allow_core_security_updates: true items: type: string domain: type: string description: '' example: null delete: summary: 'Delete Website' operationId: deleteWebsite description: "Soft-deletes a `Website` together with both of its detection groups (monitoring\nand on-demand). The underlying screenshot/comparison history is retained so\ncheck-usage counting stays correct." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: '{ID} deleted' properties: message: type: string example: '{ID} deleted' tags: - Website parameters: - in: path name: id description: 'The ID of the Website.' example: 91e9c9fd-b86f-4269-a3f4-f02810167a6d required: true schema: type: string