GHSA-4j9m-cxq4-9c36 - Improved validation Stored CSS Injection via tag_colour Field (#4317)

This commit is contained in:
dgtlmoon authored and GitHub committed 2026-08-20 17:59:02 +02:00
1 parent 50389b0778
commit 288926b44e
39 files changed
+301 -19

No files matched your search

+23
View File
@@ -10,6 +10,21 @@ from . import auth
from . import validate_openapi_request, strip_internal_api_fields
def validate_tag_colour(json_data):
"""Return an error message when tag_colour is set to anything but a hex colour.
The value is rendered into a <style> block, so anything else is CSS injection.
The OpenAPI schema carries the same pattern, this is the belt to that's braces.
"""
from changedetectionio.blueprint.tags.colour import is_safe_css_colour
tag_colour = json_data.get('tag_colour')
if tag_colour and not is_safe_css_colour(tag_colour):
return "tag_colour: must be a hex colour, for example #4f8ef7"
return None
class Tag(Resource):
def __init__(self, **kwargs):
# datastore is a black box dependency
@@ -148,6 +163,10 @@ class Tag(Resource):
if unknown_fields:
return f"Unknown field(s): {', '.join(sorted(unknown_fields))}", 400
colour_error = validate_tag_colour(json_data)
if colour_error:
return colour_error, 400
tag.update(json_data)
tag.commit()
@@ -178,6 +197,10 @@ class Tag(Resource):
if unknown_fields:
return f"Unknown field(s): {', '.join(sorted(unknown_fields))}", 400
colour_error = validate_tag_colour(json_data)
if colour_error:
return colour_error, 400
new_uuid = self.datastore.add_tag(title=title)
if new_uuid:
# Apply any extra fields (e.g. processor_config_restock_diff) beyond just title
@@ -3,6 +3,7 @@ from flask import Blueprint, request, render_template, flash, url_for, redirect
from flask_babel import gettext
from loguru import logger
from changedetectionio.blueprint.tags.colour import safe_css_colour
from changedetectionio.store import ChangeDetectionStore
from changedetectionio.flask_app import login_optionally_required
from changedetectionio.llm.evaluator import get_llm_config as _get_llm_config
@@ -11,6 +12,9 @@ from changedetectionio.llm.evaluator import get_llm_config as _get_llm_config
def construct_blueprint(datastore: ChangeDetectionStore):
tags_blueprint = Blueprint('tags', __name__, template_folder="templates")
# Used by any template that writes a tag colour into a <style> block
tags_blueprint.add_app_template_filter(safe_css_colour, 'safe_css_colour')
@tags_blueprint.route("/list", methods=['GET'])
@login_optionally_required
def tags_overview_page():
@@ -250,6 +254,13 @@ def construct_blueprint(datastore: ChangeDetectionStore):
# flash(','.join(l), 'error')
# return redirect(url_for('tags.form_tag_edit_submit', uuid=uuid))
# Until then, validate the fields that must not be taken on trust - tag_colour is
# rendered into a <style> block, where anything but a hex colour is CSS injection
if not form.tag_colour.validate(form):
for message in form.tag_colour.errors:
flash(message, 'error')
return redirect(url_for('tags.form_tag_edit', uuid=uuid))
tag.update(form.data)
tag['processor'] = 'restock_diff'
tag.commit()
@@ -0,0 +1,36 @@
"""Validation for the user supplied tag colour, which ends up inside a CSS context.
Tag colours are rendered into `<style>` blocks (watch-overview.html and
groups-overview.html). Jinja2's HTML autoescaping does not help there - CSS injection
needs none of the characters it escapes, so a value like
red} *{background-image:url(https://attacker.example.com/exfil)} .x{color:
would break out of the `background-color:` declaration and inject arbitrary rules for
every user viewing the page.
So only a plain hex colour is accepted - checked on the way in (form + API) and again
on the way out when rendering, so a value stored by an older version can't be rendered
either.
"""
import re
# What <input type="color"> produces (#rrggbb), plus the #rgb shorthand.
CSS_HEX_COLOUR_REGEX = r'^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$'
_RE_CSS_HEX_COLOUR = re.compile(CSS_HEX_COLOUR_REGEX)
def is_safe_css_colour(value) -> bool:
"""True if `value` is a hex colour that is safe to write into a CSS declaration."""
return isinstance(value, str) and bool(_RE_CSS_HEX_COLOUR.match(value.strip()))
def safe_css_colour(value) -> str:
"""Return `value` as a hex colour, or an empty string when it is not one.
Used at render time so anything unsafe falls back to the auto-generated colour
instead of being written into the stylesheet.
"""
return value.strip() if is_safe_css_colour(value) else ''
+7 -1
View File
@@ -9,6 +9,7 @@ from wtforms import (
from wtforms.fields.simple import BooleanField
from flask_babel import lazy_gettext as _l
from changedetectionio.blueprint.tags.colour import CSS_HEX_COLOUR_REGEX
from changedetectionio.processors.restock_diff.forms import processor_settings_form as restock_settings_form
from changedetectionio.llm.ui_strings import LLM_INTENT_TAG_PLACEHOLDER
from changedetectionio.llm.evaluator import (
@@ -21,7 +22,12 @@ class group_restock_settings_form(restock_settings_form):
overrides_watch = BooleanField(_l('Activate for individual watches in this tag/group?'), default=False)
url_match_pattern = StringField(_l('Auto-apply to watches with URLs matching'),
render_kw={"placeholder": _l("e.g. *://example.com/* or github.com/myorg")})
tag_colour = StringField(_l('Tag colour'), default='')
# Rendered into a <style> block, so only a plain hex colour is accepted, see colour.py
tag_colour = StringField(_l('Tag colour'),
default='',
validators=[validators.Optional(),
validators.Regexp(CSS_HEX_COLOUR_REGEX,
message=_l('Must be a hex colour, for example #4f8ef7'))])
llm_intent = TextAreaField('AI Change Intent',
validators=[validators.Optional(), validators.Length(max=2000)],
render_kw={"rows": "5", "placeholder": LLM_INTENT_TAG_PLACEHOLDER})
@@ -64,15 +64,16 @@
{% endif %}
<div class="pure-control-group">
<label>{{ _('Tag colour') }}</label>
{%- set tag_colour = data.get('tag_colour')|safe_css_colour -%}
<div style="display:flex; align-items:center; gap:0.75em;">
<input type="checkbox" id="use_custom_colour"
{% if data.get('tag_colour') %}checked{% endif %}>
{% if tag_colour %}checked{% endif %}>
<label for="use_custom_colour" style="margin:0">{{ _('Custom colour') }}</label>
<input type="color" id="tag_colour_picker"
value="{{ data.get('tag_colour') or '#4f8ef7' }}"
{% if not data.get('tag_colour') %}disabled{% endif %}>
value="{{ tag_colour or '#4f8ef7' }}"
{% if not tag_colour %}disabled{% endif %}>
<input type="hidden" name="tag_colour" id="tag_colour_hidden"
value="{{ data.get('tag_colour', '') }}">
value="{{ tag_colour }}">
</div>
<span class="pure-form-message-inline">{{ _('Leave unchecked to use the auto-generated colour based on the tag name.') }}</span>
</div>
@@ -7,8 +7,10 @@
{%- for uuid, tag in available_tags -%}
{%- if tag and tag.title -%}
{%- set class_name = tag.title|sanitize_tag_class -%}
{%- if tag.get('tag_colour') -%}
.watch-tag-list.tag-{{ class_name }} { background-color: {{ tag.tag_colour }}; color: {{ wcag_text_color(tag.tag_colour) }}; }
{#- Anything but a hex colour would inject CSS rules here, fall back to the generated colour -#}
{%- set tag_colour = tag.get('tag_colour')|safe_css_colour -%}
{%- if tag_colour -%}
.watch-tag-list.tag-{{ class_name }} { background-color: {{ tag_colour }}; color: {{ wcag_text_color(tag_colour) }}; }
{%- else -%}
{%- set colors = generate_tag_colors(tag.title) -%}
.watch-tag-list.tag-{{ class_name }} {
@@ -91,11 +91,13 @@ document.addEventListener('DOMContentLoaded', function() {
{%- for uuid, tag in tags -%}
{%- if tag and tag.title -%}
{%- set class_name = tag.title|sanitize_tag_class -%}
{%- if tag.get('tag_colour') -%}
{#- Anything but a hex colour would inject CSS rules here, fall back to the generated colour -#}
{%- set tag_colour = tag.get('tag_colour')|safe_css_colour -%}
{%- if tag_colour -%}
.button-tag.tag-{{ class_name }},
.watch-tag-list.tag-{{ class_name }} {
background-color: {{ tag.tag_colour }};
color: {{ wcag_text_color(tag.tag_colour) }};
background-color: {{ tag_colour }};
color: {{ wcag_text_color(tag_colour) }};
}
{%- else -%}
{%- set colors = generate_tag_colors(tag.title) -%}
+110
View File
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
"""
Tag colour is rendered into a <style> block, so it must only ever be a hex colour.
Anything else is stored CSS injection (GHSA-4j9m-cxq4-9c36) - Jinja2's HTML autoescaping
does not protect a CSS context, the payload below needs none of the characters it escapes.
Covers the three ways a colour can be set/rendered:
- the tag edit form
- the API (PUT and POST)
- rendering a value already in the datastore (from before this was validated)
"""
import json
from flask import url_for
from .util import get_UUID_for_tag_name
CSS_INJECTION = 'red} *{background-image:url(https://attacker.example.com/exfil)} .x{color:'
def _add_tag(client, name):
res = client.post(url_for("tags.form_tag_add"), data={"name": name}, follow_redirects=True)
assert b"Tag added" in res.data
return get_UUID_for_tag_name(client, name=name)
def test_tag_colour_form_rejects_css_injection(client, live_server, measure_memory_usage, datastore_path):
tag_uuid = _add_tag(client, "css-injection-tag")
res = client.post(
url_for("tags.form_tag_edit_submit", uuid=tag_uuid),
data={"name": "css-injection-tag", "tag_colour": CSS_INJECTION},
follow_redirects=True
)
assert b"Updated" not in res.data
assert b"Must be a hex colour" in res.data
datastore = client.application.config.get('DATASTORE')
assert not datastore.data['settings']['application']['tags'][tag_uuid].get('tag_colour')
# ..and it never reaches the stylesheet on either page that renders tag colours
for page in (url_for("watchlist.index"), url_for("tags.tags_overview_page")):
assert b"attacker.example.com" not in client.get(page).data
def test_tag_colour_form_accepts_hex(client, live_server, measure_memory_usage, datastore_path):
tag_uuid = _add_tag(client, "hex-colour-tag")
res = client.post(
url_for("tags.form_tag_edit_submit", uuid=tag_uuid),
data={"name": "hex-colour-tag", "tag_colour": "#4f8ef7"},
follow_redirects=True
)
assert b"Updated" in res.data
datastore = client.application.config.get('DATASTORE')
assert datastore.data['settings']['application']['tags'][tag_uuid].get('tag_colour') == '#4f8ef7'
res = client.get(url_for("tags.tags_overview_page"))
assert b"background-color: #4f8ef7" in res.data
# An empty value must still be allowed - that's "use the auto-generated colour"
res = client.post(
url_for("tags.form_tag_edit_submit", uuid=tag_uuid),
data={"name": "hex-colour-tag", "tag_colour": ""},
follow_redirects=True
)
assert b"Updated" in res.data
assert not datastore.data['settings']['application']['tags'][tag_uuid].get('tag_colour')
def test_tag_colour_api_rejects_css_injection(client, live_server, measure_memory_usage, datastore_path):
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
headers = {'content-type': 'application/json', 'x-api-key': api_key}
res = client.post(url_for("tag"), data=json.dumps({"title": "api-colour-tag"}), headers=headers)
assert res.status_code == 201, res.data
tag_uuid = res.json['uuid']
res = client.put(url_for("tag", uuid=tag_uuid), data=json.dumps({"tag_colour": CSS_INJECTION}), headers=headers)
assert res.status_code == 400, res.data
# Creating a tag with a bad colour in one shot must fail too
res = client.post(url_for("tag"), data=json.dumps({"title": "api-colour-tag-2", "tag_colour": CSS_INJECTION}),
headers=headers)
assert res.status_code == 400, res.data
# A hex colour is accepted and round-trips
res = client.put(url_for("tag", uuid=tag_uuid), data=json.dumps({"tag_colour": "#00ff00"}), headers=headers)
assert res.status_code == 200, res.data
assert client.get(url_for("tag", uuid=tag_uuid), headers=headers).json.get('tag_colour') == '#00ff00'
assert b"attacker.example.com" not in client.get(url_for("watchlist.index")).data
def test_tag_colour_already_stored_is_not_rendered(client, live_server, measure_memory_usage, datastore_path):
"""A value stored by an older version must still not make it into the stylesheet."""
tag_uuid = _add_tag(client, "poisoned-tag")
datastore = client.application.config.get('DATASTORE')
tag = datastore.data['settings']['application']['tags'][tag_uuid]
tag['tag_colour'] = CSS_INJECTION
tag.commit()
for page in (url_for("watchlist.index"),
url_for("tags.tags_overview_page"),
url_for("tags.form_tag_edit", uuid=tag_uuid)):
res = client.get(page)
assert res.status_code == 200
assert b"attacker.example.com" not in res.data, f"CSS injection rendered on {page}"
@@ -1309,6 +1309,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Musí být hexadecimální barva, například #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1325,6 +1325,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Muss eine Hex-Farbe sein, zum Beispiel #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1307,6 +1307,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1307,6 +1307,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1345,6 +1345,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Debe ser un color hexadecimal, por ejemplo #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1313,6 +1313,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Doit être une couleur hexadécimale, par exemple #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1309,6 +1309,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Deve essere un colore esadecimale, ad esempio #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1314,6 +1314,10 @@ msgstr "例: *://example.com/* や github.com/myorg"
msgid "Tag colour"
msgstr "タグの色"
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "16進数のカラーコードを指定してください(例: #4f8ef7)"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr "タグ名"
@@ -1315,6 +1315,10 @@ msgstr "예: *://example.com/* 또는 github.com/myorg"
msgid "Tag colour"
msgstr "태그 색상"
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "16진수 색상이어야 합니다. 예: #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr "태그 이름"
+5 -1
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: changedetection.io 0.55.8\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-08-16 18:32+0200\n"
"POT-Creation-Date: 2026-08-20 16:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1306,6 +1306,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1332,6 +1332,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Deve ser uma cor hexadecimal, por exemplo #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1396,6 +1396,10 @@ msgstr "например *://example.com/* или github.com/myorg"
msgid "Tag colour"
msgstr "Цвет тега"
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Должен быть шестнадцатеричный цвет, например #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr "Имя тега"
@@ -1342,6 +1342,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Onaltılık bir renk olmalıdır, örneğin #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1322,6 +1322,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "Має бути шістнадцятковий колір, наприклад #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1312,6 +1312,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "必须是十六进制颜色,例如 #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
@@ -1311,6 +1311,10 @@ msgstr ""
msgid "Tag colour"
msgstr ""
#: changedetectionio/blueprint/tags/form.py
msgid "Must be a hex colour, for example #4f8ef7"
msgstr "必須是十六進位色碼,例如 #4f8ef7"
#: changedetectionio/blueprint/tags/form.py
msgid "Tag name"
msgstr ""
+7
View File
@@ -811,6 +811,13 @@ components:
Supports fnmatch wildcards (* and ?): e.g. *://example.com/* or github.com/myorg.
Plain strings are matched as case-insensitive substrings.
Leave empty to disable auto-matching.
tag_colour:
type: string
pattern: '^(#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}))?$'
description: |
Background colour for this tag's badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7.
Only hex colours are accepted - the value is rendered into a CSS stylesheet.
Leave empty to use the colour auto-generated from the tag name.
# Future: Aggregated statistics from all watches with this tag
# check_count:
# type: integer
+28 -8
View File
@@ -623,8 +623,10 @@ notification preferences, and content filtering options.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Logic operator - ALL (match all conditions) or ANY (match any condition)</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_intent" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_intent</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&lt;= 2000 characters<!-- --> </span></span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;&quot;</span></div> <div><div html="&lt;p&gt;Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.</p>
</div></div></div></td></tr><tr class="last "><td kind="field" title="llm_change_summary" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&lt;= 2000 characters<!-- --> </span></span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;&quot;</span></div> <div><div html="&lt;p&gt;Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.&lt;/p&gt;
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&lt;= 2000 characters<!-- --> </span></span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;&quot;</span></div> <div><div html="&lt;p&gt;Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.</p>
</div></div></div></td></tr><tr class="last "><td kind="field" title="llm_change_summary_mode" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary_mode</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Enum<!-- -->:</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;append&quot;</span> </div> <div><div html="&lt;p&gt;Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.</p>
</div></div></div></td></tr></tbody></table><div><h3 class="sc-gDzyrw kjrVcG">Responses</h3><div><button class="sc-jIDBmd lkmdtA"><svg class="sc-dntSTA cGxVlA" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-eJvlPh fBhAXU">200<!-- --> </strong><div html="&lt;p&gt;Web page change monitor (watch) created successfully&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG"><p>Web page change monitor (watch) created successfully</p>
</div></button></div><div><button class="sc-jIDBmd ifAHvq"><svg class="sc-dntSTA jKYZgc" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-eJvlPh fBhAXU">500<!-- --> </strong><div html="&lt;p&gt;Server error&lt;/p&gt;
@@ -657,7 +659,7 @@ notification preferences, and content filtering options.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Custom server</p>
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>{protocol}://{host}/api/v1</span>/watch/{uuid}</div></div></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Request samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_2abha_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2abha_0" tabindex="0" data-rttab="true">curl</li><li class="react-tabs__tab" role="tab" id="tab_R_2abha_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2abha_1" data-rttab="true">Python</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2abha_0" aria-labelledby="tab_R_2abha_0"><div class="sc-cdmAjP gsEOpk"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button></div><pre class="sc-eVqvcJ sc-jytpVa kIppRw cCzeOT">curl <span class="token operator">-</span>X GET <span class="token string">"http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f"</span> \
<span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span>
</pre></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_2abha_1" aria-labelledby="tab_R_2abha_1"></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Response samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_2ebha_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2ebha_0" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="tab_R_2ebha_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2ebha_1" data-rttab="true">404</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2ebha_0" aria-labelledby="tab_R_2ebha_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-cCVJLD sc-gsJsQu dbfEBv ehbHlf"><svg class="sc-pYNGo eyTvTk" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg><select class="dropdown-select"><option value="application/json" selected="">application/json</option><option value="text/plain">text/plain</option></select><label>application/json</label></div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"uuid"</span>: <span class="token string">&quot;095be615-a8ad-4c33-8e9c-c7612fbf6c9f&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"date_created"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&qLine truncated
</pre></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_2abha_1" aria-labelledby="tab_R_2abha_1"></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Response samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_2ebha_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2ebha_0" tabindex="0" data-rttab="true">200</li><li class="tab-error" role="tab" id="tab_R_2ebha_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2ebha_1" data-rttab="true">404</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2ebha_0" aria-labelledby="tab_R_2ebha_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-cCVJLD sc-gsJsQu dbfEBv ehbHlf"><svg class="sc-pYNGo eyTvTk" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg><select class="dropdown-select"><option value="application/json" selected="">application/json</option><option value="text/plain">text/plain</option></select><label>application/json</label></div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"uuid"</span>: <span class="token string">&quot;095be615-a8ad-4c33-8e9c-c7612fbf6c9f&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"date_created"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&qLine truncated
" class="sc-eVqvcJ sc-fszimp kIppRw kbZred"><p>Update an existing web page change monitor (watch) using JSON. Accepts the same structure as returned in <a href="#operation/getWatch">get single watch information</a>.</p>
</div></div><div class="sc-ikkVnJ deUlC"><div class="sc-hWgKua dPSGXF"><h5 class="sc-eqYatC sc-gFqXPY czjApA jCoZLr">Authorizations:</h5><svg class="sc-dntSTA FtowP" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-jBaHRL fUkQtw"><span class="sc-iVnIWt gRXavu"><span class="sc-hqtLyI hRtRoN"><i>ApiKeyAuth</i></span></span></div></div><div><h5 class="sc-eqYatC czjApA">path<!-- --> Parameters</h5><table class="sc-eqNDNG icJLQx"><tbody><tr class="last "><td kind="field" title="uuid" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">uuid</span><div class="sc-bEjUoa sc-iIvHqT lhyyLL crXmiY">required</div></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq"> <!-- -->&lt;<!-- -->uuid<!-- -->&gt;<!-- --> </span></div> <div><div html="&lt;p&gt;Web page change monitor (watch) unique ID&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Web page change monitor (watch) unique ID</p>
@@ -775,6 +777,8 @@ notification preferences, and content filtering options.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&lt;= 2000 characters<!-- --> </span></span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;&quot;</span></div> <div><div html="&lt;p&gt;Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary_mode" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary_mode</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Enum<!-- -->:</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;append&quot;</span> </div> <div><div html="&lt;p&gt;Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.</p>
</div></div></div></td></tr><tr class="last "><td kind="field" title="last_viewed" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">last_viewed</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">integer</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&gt;= 0<!-- --> </span></span></div> <div><div html="&lt;p&gt;Unix timestamp in seconds of the last time the watch was viewed. Setting it to a value higher than &lt;code&gt;last_changed&lt;/code&gt; in the &amp;quot;Update watch&amp;quot; endpoint marks the watch as viewed.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Unix timestamp in seconds of the last time the watch was viewed. Setting it to a value higher than <code>last_changed</code> in the &quot;Update watch&quot; endpoint marks the watch as viewed.</p>
</div></div></div></td></tr></tbody></table><div><h3 class="sc-gDzyrw kjrVcG">Responses</h3><div><button class="sc-jIDBmd lkmdtA"><svg class="sc-dntSTA cGxVlA" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-eJvlPh fBhAXU">200<!-- --> </strong><div html="&lt;p&gt;Web page change monitor (watch) updated successfully&lt;/p&gt;
@@ -787,7 +791,7 @@ notification preferences, and content filtering options.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Production server</p>
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>https://yourdomain.com/api/v1</span>/watch/{uuid}</div></div></div><div class="sc-iyBeIh icOxsG"><div html="&lt;p&gt;Custom server&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Custom server</p>
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>{protocol}://{host}/api/v1</span>/watch/{uuid}</div></div></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Request samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_2acha_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2acha_0" tabindex="0" data-rttab="true">Payload</li><li class="react-tabs__tab" role="tab" id="tab_R_2acha_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acha_1" data-rttab="true">curl</li><li class="react-tabs__tab" role="tab" id="tab_R_2acha_2" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acha_2" data-rttab="true">Python</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2acha_0" aria-labelledby="tab_R_2acha_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-bAehkN iNRAJK">application/json</div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"ignore_status_codes"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_delay"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_js_execute_code"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoveLine truncated
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>{protocol}://{host}/api/v1</span>/watch/{uuid}</div></div></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Request samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_2acha_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2acha_0" tabindex="0" data-rttab="true">Payload</li><li class="react-tabs__tab" role="tab" id="tab_R_2acha_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acha_1" data-rttab="true">curl</li><li class="react-tabs__tab" role="tab" id="tab_R_2acha_2" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acha_2" data-rttab="true">Python</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2acha_0" aria-labelledby="tab_R_2acha_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-bAehkN iNRAJK">application/json</div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"ignore_status_codes"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_delay"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_js_execute_code"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoveLine truncated
" class="sc-eVqvcJ sc-fszimp kIppRw kbZred"><p>Delete a web page change monitor (watch) and all related history</p>
</div></div><div class="sc-ikkVnJ deUlC"><div class="sc-hWgKua dPSGXF"><h5 class="sc-eqYatC sc-gFqXPY czjApA jCoZLr">Authorizations:</h5><svg class="sc-dntSTA FtowP" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-jBaHRL fUkQtw"><span class="sc-iVnIWt gRXavu"><span class="sc-hqtLyI hRtRoN"><i>ApiKeyAuth</i></span></span></div></div><div><h5 class="sc-eqYatC czjApA">path<!-- --> Parameters</h5><table class="sc-eqNDNG icJLQx"><tbody><tr class="last "><td kind="field" title="uuid" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">uuid</span><div class="sc-bEjUoa sc-iIvHqT lhyyLL crXmiY">required</div></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq"> <!-- -->&lt;<!-- -->uuid<!-- -->&gt;<!-- --> </span></div> <div><div html="&lt;p&gt;Web page change monitor (watch) unique ID&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Web page change monitor (watch) unique ID</p>
@@ -1167,6 +1171,8 @@ multiple related watches.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&lt;= 2000 characters<!-- --> </span></span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;&quot;</span></div> <div><div html="&lt;p&gt;Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary_mode" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary_mode</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Enum<!-- -->:</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;append&quot;</span> </div> <div><div html="&lt;p&gt;Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="overrides_watch" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">overrides_watch</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">boolean or null</span></div> <div><div html="&lt;p&gt;Whether this tag&amp;#39;s settings override watch settings for all watches in this tag/group.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;true: Tag settings override watch settings&lt;/li&gt;
@@ -1179,7 +1185,7 @@ multiple related watches.</p>
<li>false: Tag settings do not override (watches use their own settings)</li>
<li>null: Not decided yet / inherit default behavior</li>
</ul>
</div></div></div></td></tr><tr class="last "><td kind="field" title="url_match_pattern" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">url_match_pattern</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div> <div><div html="&lt;p&gt;Automatically apply this tag to any watch whose URL matches this pattern.
</div></div></div></td></tr><tr class=""><td kind="field" title="url_match_pattern" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">url_match_pattern</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div> <div><div html="&lt;p&gt;Automatically apply this tag to any watch whose URL matches this pattern.
Supports fnmatch wildcards (* and ?): e.g. &lt;em&gt;://example.com/&lt;/em&gt; or github.com/myorg.
Plain strings are matched as case-insensitive substrings.
Leave empty to disable auto-matching.&lt;/p&gt;
@@ -1187,6 +1193,12 @@ Leave empty to disable auto-matching.&lt;/p&gt;
Supports fnmatch wildcards (* and ?): e.g. <em>://example.com/</em> or github.com/myorg.
Plain strings are matched as case-insensitive substrings.
Leave empty to disable auto-matching.</p>
</div></div></div></td></tr><tr class="last "><td kind="field" title="tag_colour" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">tag_colour</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span class="sc-bEjUoa sc-cpclqO lhyyLL UZcrz">^(#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}))?$</span></div> <div><div html="&lt;p&gt;Background colour for this tag&amp;#39;s badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7.
Only hex colours are accepted - the value is rendered into a CSS stylesheet.
Leave empty to use the colour auto-generated from the tag name.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Background colour for this tag&#39;s badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7.
Only hex colours are accepted - the value is rendered into a CSS stylesheet.
Leave empty to use the colour auto-generated from the tag name.</p>
</div></div></div></td></tr></tbody></table><div><h3 class="sc-gDzyrw kjrVcG">Responses</h3><div><button class="sc-jIDBmd lkmdtA"><svg class="sc-dntSTA cGxVlA" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg><strong class="sc-eJvlPh fBhAXU">201<!-- --> </strong><div html="&lt;p&gt;Tag created successfully&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG"><p>Tag created successfully</p>
</div></button></div><div><button class="sc-jIDBmd kQCDrg" disabled=""><strong class="sc-eJvlPh fBhAXU">400<!-- --> </strong><div html="&lt;p&gt;Invalid or unsupported tag&lt;/p&gt;
@@ -1217,7 +1229,7 @@ Leave empty to disable auto-matching.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Custom server</p>
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>{protocol}://{host}/api/v1</span>/tag/{uuid}</div></div></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Request samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_2abja_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2abja_0" tabindex="0" data-rttab="true">curl</li><li class="react-tabs__tab" role="tab" id="tab_R_2abja_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2abja_1" data-rttab="true">Python</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2abja_0" aria-labelledby="tab_R_2abja_0"><div class="sc-cdmAjP gsEOpk"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button></div><pre class="sc-eVqvcJ sc-jytpVa kIppRw cCzeOT">curl <span class="token operator">-</span>X GET <span class="token string">"http://localhost:5000/api/v1/tag/550e8400-e29b-41d4-a716-446655440000"</span> \
<span class="token operator">-</span>H <span class="token string">"x-api-key: YOUR_API_KEY"</span>
</pre></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_2abja_1" aria-labelledby="tab_R_2abja_1"></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Response samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_2ebja_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2ebja_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2ebja_0" aria-labelledby="tab_R_2ebja_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-cCVJLD sc-gsJsQu dbfEBv ehbHlf"><svg class="sc-pYNGo eyTvTk" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg><select class="dropdown-select"><option value="application/json" selected="">application/json</option><option value="text/plain">text/plain</option></select><label>application/json</label></div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"uuid"</span>: <span class="token string">&quot;095be615-a8ad-4c33-8e9c-c7612fbf6c9f&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"date_created"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"ignore_status_codes"</span>Line truncated
</pre></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_2abja_1" aria-labelledby="tab_R_2abja_1"></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Response samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="tab-success react-tabs__tab--selected" role="tab" id="tab_R_2ebja_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2ebja_0" tabindex="0" data-rttab="true">200</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2ebja_0" aria-labelledby="tab_R_2ebja_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-cCVJLD sc-gsJsQu dbfEBv ehbHlf"><svg class="sc-pYNGo eyTvTk" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg><select class="dropdown-select"><option value="application/json" selected="">application/json</option><option value="text/plain">text/plain</option></select><label>application/json</label></div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"uuid"</span>: <span class="token string">&quot;095be615-a8ad-4c33-8e9c-c7612fbf6c9f&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"date_created"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"ignore_status_codes"</span>Line truncated
" class="sc-eVqvcJ sc-fszimp kIppRw kbZred"><p>Update an existing tag using JSON</p>
</div></div><div class="sc-ikkVnJ deUlC"><div class="sc-hWgKua dPSGXF"><h5 class="sc-eqYatC sc-gFqXPY czjApA jCoZLr">Authorizations:</h5><svg class="sc-dntSTA FtowP" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-jBaHRL fUkQtw"><span class="sc-iVnIWt gRXavu"><span class="sc-hqtLyI hRtRoN"><i>ApiKeyAuth</i></span></span></div></div><div><h5 class="sc-eqYatC czjApA">path<!-- --> Parameters</h5><table class="sc-eqNDNG icJLQx"><tbody><tr class="last "><td kind="field" title="uuid" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">uuid</span><div class="sc-bEjUoa sc-iIvHqT lhyyLL crXmiY">required</div></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq"> <!-- -->&lt;<!-- -->uuid<!-- -->&gt;<!-- --> </span></div> <div><div html="&lt;p&gt;Tag unique ID&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Tag unique ID</p>
@@ -1335,6 +1347,8 @@ Leave empty to disable auto-matching.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span> <span class="sc-bEjUoa sc-goiVcJ lhyyLL bDfgbe"> <!-- -->&lt;= 2000 characters<!-- --> </span></span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;&quot;</span></div> <div><div html="&lt;p&gt;Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="llm_change_summary_mode" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">llm_change_summary_mode</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Default:<!-- --> </span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span></div><div><span class="sc-bEjUoa lhyyLL"> <!-- -->Enum<!-- -->:</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;replace&quot;</span> <span class="sc-bEjUoa sc-dTWiOz lhyyLL kMQdIk">&quot;append&quot;</span> </div> <div><div html="&lt;p&gt;Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.</p>
</div></div></div></td></tr><tr class=""><td kind="field" title="overrides_watch" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">overrides_watch</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">boolean or null</span></div> <div><div html="&lt;p&gt;Whether this tag&amp;#39;s settings override watch settings for all watches in this tag/group.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;true: Tag settings override watch settings&lt;/li&gt;
@@ -1347,7 +1361,7 @@ Leave empty to disable auto-matching.</p>
<li>false: Tag settings do not override (watches use their own settings)</li>
<li>null: Not decided yet / inherit default behavior</li>
</ul>
</div></div></div></td></tr><tr class="last "><td kind="field" title="url_match_pattern" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">url_match_pattern</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div> <div><div html="&lt;p&gt;Automatically apply this tag to any watch whose URL matches this pattern.
</div></div></div></td></tr><tr class=""><td kind="field" title="url_match_pattern" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">url_match_pattern</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span></div> <div><div html="&lt;p&gt;Automatically apply this tag to any watch whose URL matches this pattern.
Supports fnmatch wildcards (* and ?): e.g. &lt;em&gt;://example.com/&lt;/em&gt; or github.com/myorg.
Plain strings are matched as case-insensitive substrings.
Leave empty to disable auto-matching.&lt;/p&gt;
@@ -1355,6 +1369,12 @@ Leave empty to disable auto-matching.&lt;/p&gt;
Supports fnmatch wildcards (* and ?): e.g. <em>://example.com/</em> or github.com/myorg.
Plain strings are matched as case-insensitive substrings.
Leave empty to disable auto-matching.</p>
</div></div></div></td></tr><tr class="last "><td kind="field" title="tag_colour" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">tag_colour</span></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span class="sc-bEjUoa sc-cpclqO lhyyLL UZcrz">^(#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}))?$</span></div> <div><div html="&lt;p&gt;Background colour for this tag&amp;#39;s badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7.
Only hex colours are accepted - the value is rendered into a CSS stylesheet.
Leave empty to use the colour auto-generated from the tag name.&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Background colour for this tag&#39;s badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7.
Only hex colours are accepted - the value is rendered into a CSS stylesheet.
Leave empty to use the colour auto-generated from the tag name.</p>
</div></div></div></td></tr></tbody></table><div><h3 class="sc-gDzyrw kjrVcG">Responses</h3><div><button class="sc-jIDBmd oZuve" disabled=""><strong class="sc-eJvlPh fBhAXU">200<!-- --> </strong><div html="&lt;p&gt;Tag updated successfully&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp sc-etsjJW kIppRw jnwENr ljKHqG"><p>Tag updated successfully</p>
</div></button></div><div><button class="sc-jIDBmd kQCDrg" disabled=""><strong class="sc-eJvlPh fBhAXU">500<!-- --> </strong><div html="&lt;p&gt;Server error&lt;/p&gt;
@@ -1365,7 +1385,7 @@ Leave empty to disable auto-matching.</p>
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Production server</p>
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>https://yourdomain.com/api/v1</span>/tag/{uuid}</div></div></div><div class="sc-iyBeIh icOxsG"><div html="&lt;p&gt;Custom server&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Custom server</p>
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>{protocol}://{host}/api/v1</span>/tag/{uuid}</div></div></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Request samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_2acja_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2acja_0" tabindex="0" data-rttab="true">Payload</li><li class="react-tabs__tab" role="tab" id="tab_R_2acja_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acja_1" data-rttab="true">curl</li><li class="react-tabs__tab" role="tab" id="tab_R_2acja_2" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acja_2" data-rttab="true">Python</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2acja_0" aria-labelledby="tab_R_2acja_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-bAehkN iNRAJK">application/json</div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"ignore_status_codes"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_delay"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_js_execute_code"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoveraLine truncated
</div><div tabindex="0" role="button"><div class="sc-xKhEK okJpy"><span>{protocol}://{host}/api/v1</span>/tag/{uuid}</div></div></div></div></div><div><h3 class="sc-lgpSej drJHMo"> <!-- -->Request samples<!-- --> </h3><div class="sc-cOpnSz fyxuKi" data-rttabs="true"><ul class="react-tabs__tab-list" role="tablist"><li class="react-tabs__tab react-tabs__tab--selected" role="tab" id="tab_R_2acja_0" aria-selected="true" aria-disabled="false" aria-controls="panel_R_2acja_0" tabindex="0" data-rttab="true">Payload</li><li class="react-tabs__tab" role="tab" id="tab_R_2acja_1" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acja_1" data-rttab="true">curl</li><li class="react-tabs__tab" role="tab" id="tab_R_2acja_2" aria-selected="false" aria-disabled="false" aria-controls="panel_R_2acja_2" data-rttab="true">Python</li></ul><div class="react-tabs__tab-panel react-tabs__tab-panel--selected" role="tabpanel" id="panel_R_2acja_0" aria-labelledby="tab_R_2acja_0"><div><div class="sc-bSFBcf iLdyBp"><span class="sc-gahYZc cXitJ">Content type</span><div class="sc-bAehkN iNRAJK">application/json</div></div><div class="sc-blIAwI eKKwxo"><div class="sc-dClGHI fdRrNy"><div class="sc-bbbBoY bBWkcI"><button><div class="sc-fYmhhH iNCOCX">Copy</div></button><button> Expand all </button><button> Collapse all </button></div><div tabindex="0" class="sc-eVqvcJ kIppRw sc-fhfEft dFvLDb"><div class="redoc-json"><code><button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable "><span class="property token string">"url"</span>: <span class="token string">&quot;</span><a href="http://example.com">http://example.com</a><span class="token string">&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"title"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tag"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"tags"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">[</span><span class="ellipsis"></span><ul class="array collapsible"><li><div class="hoverable collapsed"><span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">]</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"paused"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"notification_muted"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"method"</span>: <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"fetch_backend"</span>: <span class="token string">&quot;system&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"headers"</span>: <button class="collapser" aria-label="collapse"></button><span class="token punctuation">{</span><span class="ellipsis"></span><ul class="obj collapsible"><li><div class="hoverable collapsed"><span class="property token string">"property1"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable collapsed"><span class="property token string">"property2"</span>: <span class="token string">&quot;string&quot;</span></div></li></ul><span class="token punctuation">}</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"body"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"proxy"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"ignore_status_codes"</span>: <span class="token boolean">true</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_delay"</span>: <span class="token number">0</span><span class="token punctuation">,</span></div></li><li><div class="hoverable "><span class="property token string">"webdriver_js_execute_code"</span>: <span class="token string">&quot;string&quot;</span><span class="token punctuation">,</span></div></li><li><div class="hoveraLine truncated
" class="sc-eVqvcJ sc-fszimp kIppRw kbZred"><p>Delete a tag/group and remove it from all web page change monitors (watches)</p>
</div></div><div class="sc-ikkVnJ deUlC"><div class="sc-hWgKua dPSGXF"><h5 class="sc-eqYatC sc-gFqXPY czjApA jCoZLr">Authorizations:</h5><svg class="sc-dntSTA FtowP" version="1.1" viewBox="0 0 24 24" x="0" xmlns="http://www.w3.org/2000/svg" y="0" aria-hidden="true"><polygon points="17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 "></polygon></svg></div><div class="sc-jBaHRL fUkQtw"><span class="sc-iVnIWt gRXavu"><span class="sc-hqtLyI hRtRoN"><i>ApiKeyAuth</i></span></span></div></div><div><h5 class="sc-eqYatC czjApA">path<!-- --> Parameters</h5><table class="sc-eqNDNG icJLQx"><tbody><tr class="last "><td kind="field" title="uuid" class="sc-kCuUfV sc-fbQrwq gdmNWp dFOJWJ"><span class="sc-hwddKA cteAyA"></span><span class="property-name">uuid</span><div class="sc-bEjUoa sc-iIvHqT lhyyLL crXmiY">required</div></td><td class="sc-gGKoUb ixGaBD"><div><div><span class="sc-bEjUoa sc-boKDdR lhyyLL jYezsP"></span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq">string</span><span class="sc-bEjUoa sc-fOOuSg lhyyLL dbKJYq"> <!-- -->&lt;<!-- -->uuid<!-- -->&gt;<!-- --> </span></div> <div><div html="&lt;p&gt;Tag unique ID&lt;/p&gt;
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr"><p>Tag unique ID</p>
@@ -1864,7 +1884,7 @@ installed processors (e.g. <code>processor_config_restock_diff</code> from the b
curl <span class="token operator">-</span>X GET <span class="token string">"http://localhost:5000/api/v1/full-spec"</span>
</pre></div></div><div class="react-tabs__tab-panel" role="tabpanel" id="panel_R_156lq_1" aria-labelledby="tab_R_156lq_1"></div></div></div></div></div></div></div><div class="sc-evkzZa iZqpqg"></div></div></div>
<script>
const __redoc_state = {"menu":{"activeItemIdx":-1},"spec":{"data":{"openapi":"3.1.0","info":{"title":"ChangeDetection.io API","description":"# ChangeDetection.io Web page monitoring and notifications API\n\nREST API for managing Page watches, Group tags, and Notifications.\n\nchangedetection.io can be driven by its built in simple API, in the examples below you will also find `curl` command line and `python` examples to help you get started faster.\n\n## Where to find my API key?\n\nThe API key can be easily found under the **SETTINGS** then **API** tab of changedetection.io dashboard. \nSimply click the API key to automatically copy it to your clipboard.\n\n![Where to find the API key](./where-to-get-api-key.jpeg)\n\n## Connection URL\n\nThe API can be found at `/api/v1/`, so for example if you run changedetection.io locally on port 5000, then URL would be `http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/history`.\n\nIf you are using the hosted/subscription version of changedetection.io, then the URL is based on your login URL, for example: \n`https://<your login url>/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/history`\n\n## Authentication\n\nAlmost all API requests require some authentication, this is provided as an **API Key** in the header of the HTTP request.\n\nFor example: `x-api-key: YOUR_API_KEY`\n","version":"0.1.7","contact":{"name":"ChangeDetection.io","url":"https://github.com/dgtlmoon/changedetection.io"},"license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"servers":[{"url":"http://localhost:5000/api/v1","description":"Development server"},{"url":"https://yourdomain.com/api/v1","description":"Production server"},{"url":"{protocol}://{host}/api/v1","description":"Custom server","variables":{"protocol":{"enum":["http","https"],"default":"https"},"host":{"default":"yourdomain.com","description":"Your changedetection.io host"}}}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Watch Management","description":"Core functionality for managing web page monitors. Create, retrieve, update, and delete individual watches. \nEach watch represents a single URL being monitored for changes, with configurable settings for check intervals, \nnotification preferences, and content filtering options.\n"},{"name":"Watch History","description":"Get a list of timestamps of all changes detected for a watch.\n"},{"name":"Snapshots","description":"Retrieve individual text snapshot of monitored content according to the `timestamp`. The text snapshot is the HTML\nto Text at page check time. \n\nSet the query argument `html` to any value to retrieve the last HTML fetched, the system only keeps the last two \n(2) HTML files fetched.\n\nUse the Watch History API endpoint to get a list of timestamps to pass to this query.\n"},{"name":"Favicon","description":"Retrieve favicon images associated with monitored web pages. These are used in the dashboard interface \nto visually identify different watches in your monitoring list.\n"},{"name":"Group / Tag Management","description":"Organize your watches using tags and groups. Tags (also known as Groups) allow you to categorize monitors, set group-wide \nnotification preferences, and perform bulk operations like mass rechecking or status changes across \nmultiple related watches.\n"},{"name":"Notifications","description":"Configure global notification endpoints that can be used across all your watches. Supports various \nnotification services including email, Discord, Slack, webhooks, and many other popular platforms. \nThese settings serve as defaults that can be overridden at the individual watch or tag level.\n\nThe notification syntax uses [https://github.com/caronc/apprise](https://github.com/caronc/apprise).\n"},{"name":"Search","description":"Search and filter your watches by URL patterns, titles, or tags. Useful for quickly finding specific \nmonitors in large collections or identifying watches that match certain criteria.\n"},{"name":"Import","description":"Bulk import multiple URLs for monitoring. Accepts plain text lists of URLs and can automatically \napply tags, proxy settings, and other configurations to all imported watches simultaneously.\n"},{"name":"System Information","description":"Retrieve system status and statistics about your changedetection.io instance, including total watch\ncounts, uptime information, and version details.\n"},{"name":"Plugin API Extensions","description":"## How Processor Plugins Extend the API\n\nchangedetection.io uses a **processor plugin** system to handle different types of change detection.\nEach processor lives in `changedetectionio/processors/<name>/` and may include an `api.yaml` file\nthat extends the core Watch schema with processor-specific configuration fields.\n\n### How it works\n\nAt startup, changedetection.io scans all installed processors for an `api.yaml` file. Any schemas\nand code samples defined there are deep-merged into the live API speciLine truncated
const __redoc_state = {"menu":{"activeItemIdx":-1},"spec":{"data":{"openapi":"3.1.0","info":{"title":"ChangeDetection.io API","description":"# ChangeDetection.io Web page monitoring and notifications API\n\nREST API for managing Page watches, Group tags, and Notifications.\n\nchangedetection.io can be driven by its built in simple API, in the examples below you will also find `curl` command line and `python` examples to help you get started faster.\n\n## Where to find my API key?\n\nThe API key can be easily found under the **SETTINGS** then **API** tab of changedetection.io dashboard. \nSimply click the API key to automatically copy it to your clipboard.\n\n![Where to find the API key](./where-to-get-api-key.jpeg)\n\n## Connection URL\n\nThe API can be found at `/api/v1/`, so for example if you run changedetection.io locally on port 5000, then URL would be `http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/history`.\n\nIf you are using the hosted/subscription version of changedetection.io, then the URL is based on your login URL, for example: \n`https://<your login url>/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/history`\n\n## Authentication\n\nAlmost all API requests require some authentication, this is provided as an **API Key** in the header of the HTTP request.\n\nFor example: `x-api-key: YOUR_API_KEY`\n","version":"0.1.7","contact":{"name":"ChangeDetection.io","url":"https://github.com/dgtlmoon/changedetection.io"},"license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"servers":[{"url":"http://localhost:5000/api/v1","description":"Development server"},{"url":"https://yourdomain.com/api/v1","description":"Production server"},{"url":"{protocol}://{host}/api/v1","description":"Custom server","variables":{"protocol":{"enum":["http","https"],"default":"https"},"host":{"default":"yourdomain.com","description":"Your changedetection.io host"}}}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Watch Management","description":"Core functionality for managing web page monitors. Create, retrieve, update, and delete individual watches. \nEach watch represents a single URL being monitored for changes, with configurable settings for check intervals, \nnotification preferences, and content filtering options.\n"},{"name":"Watch History","description":"Get a list of timestamps of all changes detected for a watch.\n"},{"name":"Snapshots","description":"Retrieve individual text snapshot of monitored content according to the `timestamp`. The text snapshot is the HTML\nto Text at page check time. \n\nSet the query argument `html` to any value to retrieve the last HTML fetched, the system only keeps the last two \n(2) HTML files fetched.\n\nUse the Watch History API endpoint to get a list of timestamps to pass to this query.\n"},{"name":"Favicon","description":"Retrieve favicon images associated with monitored web pages. These are used in the dashboard interface \nto visually identify different watches in your monitoring list.\n"},{"name":"Group / Tag Management","description":"Organize your watches using tags and groups. Tags (also known as Groups) allow you to categorize monitors, set group-wide \nnotification preferences, and perform bulk operations like mass rechecking or status changes across \nmultiple related watches.\n"},{"name":"Notifications","description":"Configure global notification endpoints that can be used across all your watches. Supports various \nnotification services including email, Discord, Slack, webhooks, and many other popular platforms. \nThese settings serve as defaults that can be overridden at the individual watch or tag level.\n\nThe notification syntax uses [https://github.com/caronc/apprise](https://github.com/caronc/apprise).\n"},{"name":"Search","description":"Search and filter your watches by URL patterns, titles, or tags. Useful for quickly finding specific \nmonitors in large collections or identifying watches that match certain criteria.\n"},{"name":"Import","description":"Bulk import multiple URLs for monitoring. Accepts plain text lists of URLs and can automatically \napply tags, proxy settings, and other configurations to all imported watches simultaneously.\n"},{"name":"System Information","description":"Retrieve system status and statistics about your changedetection.io instance, including total watch\ncounts, uptime information, and version details.\n"},{"name":"Plugin API Extensions","description":"## How Processor Plugins Extend the API\n\nchangedetection.io uses a **processor plugin** system to handle different types of change detection.\nEach processor lives in `changedetectionio/processors/<name>/` and may include an `api.yaml` file\nthat extends the core Watch schema with processor-specific configuration fields.\n\n### How it works\n\nAt startup, changedetection.io scans all installed processors for an `api.yaml` file. Any schemas\nand code samples defined there are deep-merged into the live API speciLine truncated
var container = document.getElementById('redoc');
Redoc.hydrate(__redoc_state, container);