Watchlists
A Watchlist is a named collection of monitoring sources (accounts, hashtags, keywords) attached to an agent. Scraped data feeds back into agent chat and content idea generation — query results conversationally, not from this surface.
Base URL: https://agent-core.gen.pro/v1
Authentication
Section titled “Authentication”Same as the rest of the API: pass your API key in the X-API-Key header. JWT authentication (Authorization: Bearer <token>) is also supported. See Authentication for how to mint an API key.
Mental model
Section titled “Mental model”Agent ──┬── Watchlist "crypto watch" (intent_active=true) │ ├── WatchSource (tiktok, keyword, "btc") │ ├── WatchSource (tiktok, keyword, "eth") │ └── WatchSource (tiktok, hashtag, "crypto") │ └── Watchlist "competitors" (intent_active=true) ├── WatchSource (tiktok, account, "drunkelephant") └── WatchSource (instagram, account, "drunkelephant")- A
WatchSourceis a(platform, target_type, target_value)triple.target_typeis one ofaccount,hashtag, orkeyword. - Watchlist creation is idempotent on name within an agent (case-insensitive): re-posting the same name merges the sources you provide into the existing watchlist instead of creating a duplicate.
- Adding the same source twice is also idempotent — the existing row is returned (or restored if it had been soft-deleted).
- Management calls are free. Downstream scrapes bill normally when results are pulled into chat or generation.
Endpoints
Section titled “Endpoints”GET /v1/agents/:agent_id/watchlists
Section titled “GET /v1/agents/:agent_id/watchlists”List active watchlists for the agent, newest first. Soft-deleted watchlists are filtered out.
curl "https://agent-core.gen.pro/v1/agents/$AGENT_ID/watchlists" \ -H "X-API-Key: $GEN_API_KEY"import { gen } from "@poweredbygen/gen-sdk";const { sdk } = gen({ apiKey: process.env.GEN_API_KEY! });const watchlists = await sdk.monitoring.listWatchlists(agentId);POST /v1/agents/:agent_id/watchlists
Section titled “POST /v1/agents/:agent_id/watchlists”Create a watchlist, optionally with initial sources. Idempotent on name.
curl -X POST "https://agent-core.gen.pro/v1/agents/$AGENT_ID/watchlists" \ -H "X-API-Key: $GEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "crypto watch", "sources": [ { "platform": "tiktok", "target_type": "keyword", "target_value": "btc" }, { "platform": "tiktok", "target_type": "keyword", "target_value": "sui" } ] }'const watchlist = await sdk.monitoring.createWatchlist(agentId, { name: "crypto watch", sources: [ { platform: "tiktok", target_type: "keyword", target_value: "btc" }, { platform: "tiktok", target_type: "keyword", target_value: "sui" }, ],});Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string (1-200) | yes | Display name. Re-using the same name within an agent merges sources into the existing watchlist. |
sources | array | no | Initial sources to monitor. See WatchSource schema below. |
project_id | string | integer | no | Optional project to link this watchlist to. |
conversation_id | string | no | Optional chat conversation that triggered creation (attribution). |
created_by_run_id | string | no | Optional agent_run that triggered creation (attribution). |
Response (201): the full Watchlist object with its sources.
GET /v1/agents/:agent_id/watchlists/:watchlist_id
Section titled “GET /v1/agents/:agent_id/watchlists/:watchlist_id”Fetch one watchlist with its full active sources list.
PATCH /v1/agents/:agent_id/watchlists/:watchlist_id
Section titled “PATCH /v1/agents/:agent_id/watchlists/:watchlist_id”Update mutable fields. Use this endpoint with intent_active=false/true to pause/resume monitoring without deleting the watchlist.
# Pause monitoring (sources retained, scheduler stops queueing)curl -X PATCH "https://agent-core.gen.pro/v1/agents/$AGENT_ID/watchlists/$WL_ID" \ -H "X-API-Key: $GEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "intent_active": false }'await sdk.monitoring.pauseWatchlist(agentId, watchlistId);await sdk.monitoring.resumeWatchlist(agentId, watchlistId);await sdk.monitoring.updateWatchlist(agentId, watchlistId, { name: "crypto watch v2" });Updatable fields: name, intent_active, project_id.
DELETE /v1/agents/:agent_id/watchlists/:watchlist_id
Section titled “DELETE /v1/agents/:agent_id/watchlists/:watchlist_id”Soft-delete: marks the watchlist and all its sources inactive and deleted. Use PATCH with intent_active=false for a reversible pause.
POST /v1/agents/:agent_id/watchlists/:watchlist_id/sources
Section titled “POST /v1/agents/:agent_id/watchlists/:watchlist_id/sources”Add or restore a source on a watchlist. Idempotent on (platform, target_type, target_value).
curl -X POST "https://agent-core.gen.pro/v1/agents/$AGENT_ID/watchlists/$WL_ID/sources" \ -H "X-API-Key: $GEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "platform": "tiktok", "target_type": "hashtag", "target_value": "ethereum" }'await sdk.monitoring.addWatchlistSource(agentId, watchlistId, { platform: "tiktok", target_type: "hashtag", target_value: "ethereum",});DELETE source
Section titled “DELETE source”Two equivalent forms — by source id (preferred), or by the (platform, target_type, target_value) key.
# by idcurl -X DELETE "https://agent-core.gen.pro/v1/agents/$AGENT_ID/watchlists/$WL_ID/sources/$SRC_ID" \ -H "X-API-Key: $GEN_API_KEY"
# by keycurl -X DELETE "https://agent-core.gen.pro/v1/agents/$AGENT_ID/watchlists/$WL_ID/sources?platform=tiktok&target_type=keyword&target_value=btc" \ -H "X-API-Key: $GEN_API_KEY"await sdk.monitoring.removeWatchlistSource(agentId, watchlistId, { sourceId });// orawait sdk.monitoring.removeWatchlistSource(agentId, watchlistId, { platform: "tiktok", target_type: "keyword", target_value: "btc",});Schemas
Section titled “Schemas”WatchSourceInput
Section titled “WatchSourceInput”| Field | Type | Required | Description |
|---|---|---|---|
platform | string | yes | e.g. "tiktok", "instagram", "youtube" |
target_type | "account" | "hashtag" | "keyword" | yes | Kind of source |
target_value | string | yes | @handle, hashtag name (no #), or keyword text |
original_display_value | string | null | no | Optional original form (e.g. "#glassskin") |
Watchlist
Section titled “Watchlist”{ "id": "uuid", "user_id": "string", "agent_id": "uuid", "name": "crypto watch", "intent_active": true, "project_id": null, "project_error": null, "conversation_id": null, "created_by_run_id": null, "sources": [ { "id": "uuid", "watchlist_id": "uuid", "agent_id": "uuid", "platform": "tiktok", "target_type": "keyword", "target_value": "btc", "original_display_value": null, "intent_active": true, "created_at": "2026-05-27T19:00:00Z", "updated_at": "2026-05-27T19:00:00Z" } ], "created_at": "2026-05-27T19:00:00Z", "updated_at": "2026-05-27T19:00:00Z"}Errors
Section titled “Errors”| Status | Code | Description |
|---|---|---|
| 401 | unauthorized | Missing or invalid API key |
| 404 | not_found | Agent not found, or watchlist/source soft-deleted |
| 422 | validation_error | Request body failed validation |
Query a watchlist with typed filters
Section titled “Query a watchlist with typed filters”For programmatic asks where you’d rather build a typed parameter object than a natural-language prompt, the SDK and MCP both ship a queryWatchlist primitive that wraps the chat path with structured fields.
# Equivalent natural-language ask: "top 30 videos from @list:<watchlist_id> by engagement rate in the last 90 days"curl -X POST "https://agent.gen.pro/v1/agent/run" \ -H "X-API-Key: $GEN_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"agent_id\":\"$AGENT_ID\",\"message\":\"top 30 videos from @list:$WL_ID by engagement rate in the last 90 days\"}"import { gen } from "@poweredbygen/gen-sdk";const { sdk } = gen({ apiKey: process.env.GEN_API_KEY! });
const run = await sdk.monitoring.queryWatchlist(agentId, watchlistId, { question: "top videos", limit: 30, days: 90, sort_by: "engagement_rate",});Parameters (all optional except question):
| Field | Type | Description |
|---|---|---|
question | string (required) | What to ask. Drives the analysis kind — "top videos" / "top hooks" / "top creators" / "trending music" / "comment themes". |
days | integer 1-365 | Time window. Out-of-range values return a chat clarifier (“you said N; I can search 1-365”). |
limit | integer 1-1000 | How many results to return. Out-of-range values clarify. |
sort_by | engagement_rate | watch_count | like_count | comment_count | share_count | save_count | posted_at | trending_score | Sort key. Omit for backend default ranking. |
min_engagement_rate | number 0.0-1.0 | Threshold as a fraction. 0.05 filters to videos with engagement rate above 5%. |
return_all | boolean | Walk every matching row up to the maximum of 1000 results. Without an explicit limit, lifts the per-call ceiling. |
Response: a run record with a run_id. Poll the run with getRunStatus until status === "completed"; the final answer payload contains a video grid block plus a natural-language summary that respects the filters.
Filter semantics — no silent caps:
- Every filter you state is honored byte-identically across all of the watchlist’s sources.
- If you omit a filter, the chat-side default policy applies in exactly one place —
limitdefaults to 100;days/sort_by/min_engagement_ratestay unset so the backend’s own behavior shows through. - When
return_all=trueis set without an explicitlimit, the request walks up to the maximum of 1000 rows. - Stating both
return_all=trueandlimit=Nhonors the explicit cap. - Stating values outside the schema’s allowed range surfaces a chat clarifier instead of silently dropping the filter.