Monitors
Saved /v1/search or /v1/news requests that run hourly, daily or weekly and report only results they haven't seen before, or /v1/webpage URLs reported when their content changes: in the run history, and to a signed monitor.results webhook when one is set.
POST
https://api.serpkite.com/v1/monitors
Credits: 1 per run, priced like the search or page fetch it makes (1 per 10 results, num=100 is 7); empty and failed runs are free
A monitor saves a /v1/search or /v1/news request and runs it on a schedule (interval: hourly, daily or weekly, or interval_seconds from 1 hour to 30 days). Each run reports only the results among the top num it hasn't seen before. With endpoint: "webpage" and a url, it checks that page instead and reports it (change: new|changed, with its Markdown) whenever the content changes.
New results are always kept in the monitor's run history (GET /v1/monitors/{id}/runs, results for 24 hours) and, when the monitor has a webhook_url, posted as a signed monitor.results event. The first run is due right away and reports everything it finds (first_run: true).
Each run is billed like the request it makes (1 credit per 10 results, num: 100 is 7; empty and failed runs are free) on the monitor's API key: the key that created it, or last changed or ran it, under that key's limits and the account's spend cap. A monitor pauses itself after 10 failed runs in a row or when its key is revoked; PATCH it with active: true to resume.
A monitor keeps only the fields listed below; any other search field (tbs, start_date, include_content…) is a 400.
Request body
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | The query, for search and news monitors. | |
url | string | The page to watch, for endpoint: "webpage". |
|
endpoint | string | search | What to run. One of: search, news, webpage. |
interval | string | daily | How often to run. One of: hourly, daily, weekly. |
interval_seconds | integer | Exact interval, 3,600–2,592,000 seconds. Overrides interval. |
|
webhook_url | string | Receives signed monitor.results events. Without one, read new results from the run history. |
|
name | string | Your label, up to 200 characters. | |
active | boolean | true | false creates the monitor paused. |
metadata | object | Your own JSON object (up to 2 KB), echoed on the monitor and in its webhooks. | |
country | string | us | Country to search from, as a two-letter ISO code (us, gb, de, in…). Defaults to the country a location ends in. |
language | string | en | Interface language, as a language code with an optional region (en, de, pt-BR, zh-TW…). |
location | string | Canonical location for local results, e.g. "Austin, Texas, United States". Ending in a country name also sets country. | |
time | string | Restrict to recent results. Shorthand for tbs=qdr:*. One of: hour, day, week, month, year. |
|
num | integer | Watch only the top num results (1–100). |
|
device | string | desktop | Which SERP layout to fetch. One of: desktop, mobile. |
safe | string | off | SafeSearch filtering. One of: off, active. |
include_domains | string[] | Only results from these sources, up to 20: a domain (example.com, subdomains match), a path prefix (github.com/org) or a TLD (.gov). Compiled to site: operators and enforced on the results. Search, news, images, videos. | |
exclude_domains | string[] | Drop results from these sources, up to 20, same formats as include_domains. Search, news, images, videos. | |
engine | string or array | google | Which search providers may answer. google is Google only (SerpKite still fails over across its own proxy pools); auto falls back to other providers when Google is blocked or times out; consensus (search only) asks several independent indexes in parallel, merges the results by URL, ranks them by agreement and lists each result's sources, at the sum of one page per provider that returned results; a provider name or a list (e.g. google,brave) restricts the request to those. meta.engine names the provider that answered. One of: google, auto, consensus, brave, bing, yahoo, duckduckgo, mojeek, wikipedia. |
Example request
Authenticate with Authorization: Bearer $SERPKITE_API_KEY (GET requests may pass
?api_key= instead). The official SDKs read
SERPKITE_API_KEY for you. See Authentication.
curl https://api.serpkite.com/v1/monitors \
-H "Authorization: Bearer $SERPKITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"q":"ai agents funding","endpoint":"news","interval":"daily","webhook_url":"https://example.com/hooks/serpkite"}'Response fields
| Field | Type | Description |
|---|---|---|
id | string | The monitor's ID, for GET, PATCH, DELETE /v1/monitors/{id}, POST /v1/monitors/{id}/run (run at the next poll, within about 30 seconds) and GET /v1/monitors/{id}/runs. |
request | object | The saved search (q and options) or watched url. |
interval_seconds / next_run_at / last_run_at | mixed | The schedule. |
last_status / last_error / last_new_results | mixed | The last run: ok, error, webhook_failed or paused, and how many new results it found. |
runs / consecutive_failures / credits_used | number | Totals over all runs; the failure streak pauses the monitor at 10. |
Every billed response also carries credit and latency headers
(X-Credits-Used, X-Credits-Remaining, X-Request-Id…).
Example response
{
"id": "01926a3e-9d1f-7a2b-8c3d-4e5f6a7b8c9d",
"name": "",
"endpoint": "news",
"request": {
"q": "ai agents funding"
},
"metadata": null,
"interval_seconds": 86400,
"webhook_url": "https://example.com/hooks/serpkite",
"active": true,
"next_run_at": "2026-10-04T12:00:00Z",
"last_run_at": "2026-10-03T12:00:05Z",
"last_status": "ok",
"last_error": null,
"last_new_results": 10,
"runs": 1,
"consecutive_failures": 0,
"credits_used": 1,
"created_at": "2026-10-03T12:00:00Z"
}Errors
Errors use one shape: {"error":{"code","message","request_id"}}. Errors are never billed.
Full list in Errors.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A parameter is missing or invalid. |
| 401 | unauthorized | The API key is missing, invalid or revoked. |
| 402 | insufficient_credits | Your balance is too low. Buy a pack or wait for the monthly free grant. |
| 429 | rate_limited | Too many requests per second for your plan. Retry after the Retry-After header. |
| 503 | upstream_error | Google could not be fetched or parsed. Not billed; retry after Retry-After. |
Notes
- At most 100 monitors per account (
403 forbiddenbeyond that). - Run now (
POST /v1/monitors/{id}/run) requires an active monitor. A paused monitor returns409 invalid_request; resume it withPATCH {"active": true}, which also schedules an immediate run. - Changing the saved search with
PATCHstarts a new baseline: the next run reports every result as new. - To spot new results a monitor keeps only hashes of the links it has reported; the new results themselves stay in the run history for 24 hours. See Privacy and data retention.