Hotel monitor endpoints require a paid plan (Starter or higher). Without one, these endpoints return
402 plan_upgrade_required. See Pricing for details.extract schema to define, since a hotel monitor always watches the property’s cheapest available room rate. A monitor created here is also visible via GET /v1/monitors/{id}.
Endpoints
Available under both/v1/booking/monitors and /v1/agoda/monitors — the prefix only matters for creating a single-channel monitor; everything else (including a channels monitor) is reachable through either:
POST /v1/booking/monitors/POST /v1/agoda/monitors— Create a monitor.GET .../monitors— List monitors.GET .../monitors/{id}— Get monitor detail.PATCH .../monitors/{id}— Update dates, occupancy, currency, cron, watch config, name, webhook, or active state.DELETE .../monitors/{id}— Delete a monitor.POST .../monitors/{id}/trigger— Run immediately and synchronously (returns{run_id, status}once the check completes — unlike the generic monitors trigger, which queues async).GET .../monitors/{id}/runs/GET .../monitors/{id}/runs/latest— Run history.GET .../monitors/{id}/changes/GET .../monitors/{id}/changes/latest— Detected price-change history, newest first.
Creating a single-channel monitor
property_id (the /hotel/xx/property-slug.html segment). Agoda identifies it with url (the full property URL) instead — see Agoda’s property resolution if you only have a numeric property_id and city_id.
watch.thresholds ({abs, pct}) filters out rounding noise — only a move past the absolute or percentage threshold (whichever comes first) counts as a real change and fires monitor.change_detected.
Cross-provider channels monitors
Hotels are contractually required to keep prices consistent across channels. A channels monitor watches the same property on both Booking.com and Agoda in one request and computes the spread every run, instead of you diffing two separate single-property monitors yourself. Pass channels (2-4 entries, one per provider, no duplicate providers) instead of a single property_id/url:
channels[].property_id holds the identifying string for that leg regardless of provider — for an Agoda channel entry, pass the full property URL in property_id (Agoda’s own field-name convention of url doesn’t apply inside channels). The endpoint you POST to (/v1/booking/monitors or /v1/agoda/monitors) doesn’t matter for a channels monitor — neither provider “owns” it, and it’s readable/updatable/deletable/triggerable through either router. channels itself can’t be changed later via PATCH; only dates, occupancy, currency, cron, watch, name, webhook, and active state are mutable after creation.
watch.parity_threshold ({abs, pct}, channels monitors only) controls when a monitor.rate_parity_alert webhook fires, separately from watch.thresholds (which, for channels, is keyed by provider — e.g. {booking: {abs, pct}, agoda: {abs, pct}} — and controls per-channel monitor.change_detected events).
Webhook events
monitor.change_detected— a watched price moved past its threshold. Booking single-channel monitors get a price-shaped payload (previous_price,current_price,diff,params); Agoda single-channel andchannelsmonitors currently get the generic diff-engine shape (changes: [{field, previous_value, new_value}]) instead — readGET .../monitors/{id}/changesfor a normalized hotel view of any provider.monitor.rate_parity_alert—channels-only. Fires when the spread between channels crosseswatch.parity_threshold:
watch configuration model (digest delivery, notify_on_first_run) and webhook envelope shape.