---
title: "Create a monitor — a saved /v1/search or /v1/news request (new results) or a /v1/webpage URL (content changes) that runs on a schedule and reports what is new (signed webhook and run history)"
method: POST
path: "/v1/monitors"
---

# Create a monitor — a saved /v1/search or /v1/news request (new results) or a /v1/webpage URL (content changes) that runs on a schedule and reports what is new (signed webhook and run history)

`POST /v1/monitors`

## Request

- Base URL: `https://api.serpkite.com`
- URL: `https://api.serpkite.com/v1/monitors`
- Auth: HTTP bearer

Runs hourly to monthly (`interval` or `interval_seconds`, default daily); the
first run is due right away (unless `active: false`). With `endpoint: webpage`
the monitor watches `url` and reports the page (Markdown, `change: new|changed`)
whenever its content changes (1 credit per check). Each run is billed like the
search it makes (1 credit per 10 results, `num: 100` is 7; empty and failed runs
are free) on the monitor's key: the key that created it, or last changed or ran
it, under that key's limits and the account's spend cap. Only the fields below
are kept; any other search field is a `400`. Results among the
top `num` not seen in earlier runs are POSTed as a `monitor.results` webhook when
the monitor has a `webhook_url`, and are always listed in its run history
(`GET /v1/monitors/{id}/runs`, results kept 24 hours). At most 100 monitors per
account (403 `forbidden`). A monitor pauses itself after 10 failed runs in a row
(search errors, insufficient credits or webhook failures) or when its key is
revoked; set `active: true` to resume.

## Request body

- MonitorCreateRequest: Search and news monitors need `q`; webpage monitors need `url` and take only `country` besides
  - `q` string
  - `url` string, uri: endpoint=webpage: the page to watch for content changes
  - `endpoint` 'search' | 'news' | 'webpage'
  - `metadata` object: Your own JSON object (at most 2 KB), echoed on the monitor and in its webhooks
  - `name` string
  - `interval` 'hourly' | 'daily' | 'weekly'
  - `interval_seconds` integer: Overrides interval
  - `webhook_url` string, uri: Receives signed `monitor.results` events. Without one, read new results from the run history
  - `active` boolean: false creates the monitor paused
  - `country` string
  - `language` string
  - `location` string
  - `time` 'hour' | 'day' | 'week' | 'month' | 'year'
  - `num` integer
  - `device` 'desktop' | 'mobile'
  - `safe` 'active' | 'off'
  - `include_domains` union: Domains as an array or a comma-separated string, at most 20: a host (`example.com`, subdomains match), a host with a path prefix (`github.com/org`) or a TLD (`.gov`).
    - string
    - string[]
  - `exclude_domains` union: Domains as an array or a comma-separated string, at most 20: a host (`example.com`, subdomains match), a host with a path prefix (`github.com/org`) or a TLD (`.gov`).
    - string
    - string[]
  - `engine` union: Which search providers may answer. `google` (the default) is Google only; within Google, SerpKite always fails over across its own proxy pools. `auto` allows falling back to other enabled providers, in route order, when Google is blocked or times out. A single other provider (`brave`) or a list (`["google","brave"]`, or `google,brave` in a query string) restricts the request to those providers. `meta.engine` always names the provider that answered and credits follow that provider's price. A key with "Allow fallback to other search engines" on treats a request without `engine` as `auto`. `consensus` (`/v1/search` only; 400 elsewhere, and it can't be combined with other names) queries several independent search indexes in parallel (at most one Bing-backed provider, so Yahoo or DuckDuckGo never count as agreeing with Bing), merges the results by URL and ranks them by how many providers returned each one. Each result lists its `sources`; `meta.engine` is `consensus` and `meta.route` lists every provider attempt. It stops once `num` unique results are in hand or after a few seconds, and costs the sum of one page at each provider that returned results (providers that failed, came back empty or were never started are free).
    - string
    - Provider[]

## Response `201`

Created

- Monitor
  - `id` string, uuid, required
  - `name` string, required
  - `endpoint` 'search' | 'news' | 'webpage', required
  - `request` MonitorSearch, required: The saved request a monitor reruns: a search (q and options) or, for webpage monitors, url (and country)
    - `q` string
    - `url` string
    - `country` string
    - `language` string
    - `location` string
    - `time` 'hour' | 'day' | 'week' | 'month' | 'year'
    - `num` integer
    - `device` string
    - `safe` string
    - `include_domains` string[]
    - `exclude_domains` string[]
    - `engine` string[]
  - `metadata` object, nullable
  - `interval_seconds` integer, required
  - `webhook_url` string, nullable, required: Null when new results are only kept in the run history
  - `active` boolean, required
  - `next_run_at` string, date-time, required
  - `last_run_at` string, date-time, nullable
  - `last_status` 'ok' | 'error' | 'webhook_failed' | 'paused' | 'null', nullable
  - `last_error` string, nullable
  - `last_new_results` integer: New results found by the last run
  - `runs` integer, required
  - `consecutive_failures` integer, required: Failed runs in a row; the monitor pauses itself at 10
  - `credits_used` number, required: Total over all runs
  - `created_at` string, date-time, required

## Other responses

- `400`: Error
- `401`: Error
- `403`: Error
- `429`: Error

---

[API](https://skmtc.dev/serpkite/apis/serpkite-serp-api.md) · [All operations](https://skmtc.dev/serpkite/apis/serpkite-serp-api/llms.txt) · [OpenAPI document](https://skmtc.dev/serpkite/apis/serpkite-serp-api/revisions/f2c6dd05cfc5?raw)
