Skip to content

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

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.

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 WatchSource is a (platform, target_type, target_value) triple. target_type is one of account, hashtag, or keyword.
  • 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.

List active watchlists for the agent, newest first. Soft-deleted watchlists are filtered out.

Terminal window
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);

Create a watchlist, optionally with initial sources. Idempotent on name.

Terminal window
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:

FieldTypeRequiredDescription
namestring (1-200)yesDisplay name. Re-using the same name within an agent merges sources into the existing watchlist.
sourcesarraynoInitial sources to monitor. See WatchSource schema below.
project_idstring | integernoOptional project to link this watchlist to.
conversation_idstringnoOptional chat conversation that triggered creation (attribution).
created_by_run_idstringnoOptional 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.

Terminal window
# 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).

Terminal window
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",
});

Two equivalent forms — by source id (preferred), or by the (platform, target_type, target_value) key.

Terminal window
# by id
curl -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 key
curl -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 });
// or
await sdk.monitoring.removeWatchlistSource(agentId, watchlistId, {
platform: "tiktok",
target_type: "keyword",
target_value: "btc",
});
FieldTypeRequiredDescription
platformstringyese.g. "tiktok", "instagram", "youtube"
target_type"account" | "hashtag" | "keyword"yesKind of source
target_valuestringyes@handle, hashtag name (no #), or keyword text
original_display_valuestring | nullnoOptional original form (e.g. "#glassskin")
{
"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"
}
StatusCodeDescription
401unauthorizedMissing or invalid API key
404not_foundAgent not found, or watchlist/source soft-deleted
422validation_errorRequest body failed validation

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.

Terminal window
# 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):

FieldTypeDescription
questionstring (required)What to ask. Drives the analysis kind — "top videos" / "top hooks" / "top creators" / "trending music" / "comment themes".
daysinteger 1-365Time window. Out-of-range values return a chat clarifier (“you said N; I can search 1-365”).
limitinteger 1-1000How many results to return. Out-of-range values clarify.
sort_byengagement_rate | watch_count | like_count | comment_count | share_count | save_count | posted_at | trending_scoreSort key. Omit for backend default ranking.
min_engagement_ratenumber 0.0-1.0Threshold as a fraction. 0.05 filters to videos with engagement rate above 5%.
return_allbooleanWalk 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 — limit defaults to 100; days / sort_by / min_engagement_rate stay unset so the backend’s own behavior shows through.
  • When return_all=true is set without an explicit limit, the request walks up to the maximum of 1000 rows.
  • Stating both return_all=true and limit=N honors the explicit cap.
  • Stating values outside the schema’s allowed range surfaces a chat clarifier instead of silently dropping the filter.