Watch an app, a set of competitors or a set of keywords and get events when something significant changes.
Use this when the user wants to be told about changes ("tell me when a competitor updates", "alert me when my rating drops", "track my ranks for these keywords"). Kinds:
app{ app }: new versions, metadata / price changes, featuring, rating drops, review and ratings spikes, chart entries for that app.competitor_set{ app?, competitors[] }: the same for every app in the set (your ownappoptional).keyword{ terms[], store, app? }: search-rank moves ofappfor each term (rank_change) and new apps in the top N (keyword_entrant). Watched apps (competitors included) count againstlimits.watches; keyword watches use one keyword slot per term × store × country (limits.keywords). Exceeding either returns 402 plan_limit and changes nothing. Watched apps are refreshed daily. Events appear atGET /v1/eventsand go to your webhooks.
Request
curl -X POST "https://api.appgoat.ai/v1/watches" \
-H "x-api-key: $APPGOAT_API_KEY" \
-H "content-type: application/json" \
-d '{"kind":"app","name":"string","app":"string","competitors":["string"],"terms":["string"],"term":"photo editor","store":"apple","countries":["us"],"event_types":["new_version"],"settings":{"significance":0.5,"rank_move":5,"keyword_top_n":10,"chart_top_n":100,"rating_drop":0.1,"spike_factor":3,"email_digest":true,"depth":1,"cadence_minutes":1},"active":true}'const res = await fetch("https://api.appgoat.ai/v1/watches", {
method: 'POST',
headers: {
"x-api-key": process.env.APPGOAT_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({"kind":"app","name":"string","app":"string","competitors":["string"],"terms":["string"],"term":"photo editor","store":"apple","countries":["us"],"event_types":["new_version"],"settings":{"significance":0.5,"rank_move":5,"keyword_top_n":10,"chart_top_n":100,"rating_drop":0.1,"spike_factor":3,"email_digest":true,"depth":1,"cadence_minutes":1},"active":true}),
});
const { data, meta } = await res.json();import os, requests
res = requests.post(
"https://api.appgoat.ai/v1/watches",
headers={"x-api-key": os.environ["APPGOAT_API_KEY"]},
json={"kind":"app","name":"string","app":"string","competitors":["string"],"terms":["string"],"term":"photo editor","store":"apple","countries":["us"],"event_types":["new_version"],"settings":{"significance":0.5,"rank_move":5,"keyword_top_n":10,"chart_top_n":100,"rating_drop":0.1,"spike_factor":3,"email_digest":True,"depth":1,"cadence_minutes":1},"active":True}
)
body = res.json()Request body
JSON, required.
kindWatchKindnamestring | nullappstringAny
{app} input. app: required; competitor_set: your own app (optional); keyword: the app whose ranks to report (optional).competitorsstring[]competitor_set only.
termsstring[]keyword only (or
term).termstringstore"apple" | "play" | "both"keyword watches without app (default both); also disambiguates app inputs.
countriesstring[]event_typesEventType[] | nullnull = every type of the kind.
settingsWatchSettingsactivebooleanResponse
201 with data: Watch. See the envelope for meta.
idintegerkindWatchKindnamestring | nullstore"apple" | "play" | "both" | nullappanycompetitorsWatchApp[]competitor_set only.
termsstring[]keyword only.
keywordsobject[]keyword only: one slot per store × country × term (id = the tracked-keyword id).
keywords[].idintegerkeywords[].termstringkeywords[].storeStorekeywords[].countrystringkeywords[].ranked_atstring | nullcountriesstring[]event_typesEventType[]settingsWatchSettingsactivebooleancreated_atstringupdated_atstringExample
{
"data": {
"id": 1,
"kind": "app",
"name": "string",
"store": "apple",
"app": null,
"competitors": [
{
"store": "apple",
"app_id": "324684580",
"title": "Spotify: Music and Podcasts",
"icon_url": "string",
"developer_name": "string"
}
],
"terms": [
"string"
],
"keywords": [
{
"id": 1,
"term": "photo editor",
"store": "apple",
"country": "us",
"ranked_at": "2026-10-22T10:00:00Z"
}
],
"countries": [
"string"
],
"event_types": [
"new_version"
],
"settings": {
"significance": 0.5,
"rank_move": 5,
"keyword_top_n": 10,
"chart_top_n": 100,
"rating_drop": 0.1,
"spike_factor": 3,
"email_digest": true,
"depth": 1,
"cadence_minutes": 1
},
"active": false,
"created_at": "2026-10-22T10:00:00Z",
"updated_at": "2026-10-22T10:00:00Z"
},
"meta": {
"credits_used": 0,
"credits_remaining": 9981,
"request_id": "req_123"
}
}Status codes
201
The watch.
A parameter is missing or invalid (
error.param names it).Missing or invalid API key.
insufficient_credits (the call costs more than you have left; nothing was done) or plan_limit (a feature of a higher plan).Nothing matches
{app}, or the store does not have it.429
rate_limitedToo many requests per second for your plan.