Scheduled reports
How brands, scheduled reports, region configs and prompts fit together to power recurring AI visibility tracking.
Recurring AI visibility tracking in Rank Prompt is built on a four-level hierarchy: brand → scheduled report → region config → prompts. Once you understand how the four resources nest, the rest of the API is just CRUD.
This page is a conceptual overview. For the exact request shapes, jump to the Scheduled reports and Region configs sections of the reference.
The hierarchy
brand
└── scheduled report (cadence: daily / weekly / monthly)
└── region config (×N) (one per market: country + language + AI platforms)
└── prompts (×M) (the questions we ask each AI platform)
Every tick of the scheduler materialises one report per active region config attached to the schedule. So a weekly schedule with 3 region configs produces 3 fresh reports every week, each containing the prompts seeded on its region config.
Brand
A brand is the top-level container for everything we track. It owns its
researched facts, its categories, the aliases the analyzer counts as brand
mentions, and every report (one-off or recurring) below it. See
POST /v1/brands.
Scheduled report
A scheduled report defines the cadence at which we want to refresh visibility data:
frequency:daily,weeklyormonthly.next_run_at: computed fromfrequencyon creation; you can override it viaPATCHto anchor a run to a specific moment.is_active: pause/resume without deleting history.
A schedule by itself doesn’t ask any questions yet; it’s the cadence
container. You attach region configs to it to define what it actually
runs. See
POST /v1/scheduled-reports.
The fastest setup passes region_configs in that same call: every market
(country, optional city, language, AI platforms) with its own prompts, or
with the prompts of a finished report through source_report_id and
copy_report_prompts: true. Up to 20 of them, created all or nothing. The
schedule is active as soon as one of them has prompts. Created without
region_configs, a schedule starts inactive and wakes up by itself when
you attach its first active region config, so a schedule with no markets
never runs and never bills.
Duplicating a schedule
POST /v1/scheduled-reports/{id}/duplicates with a name and a frequency
creates a new schedule from an existing one: its client delivery settings,
every region config (country, city, language, AI platforms, active state) and
each config’s active prompts are copied; past runs are not. Use it to track
the same markets on another cadence. A copy of a paused schedule stays
paused.
Manual runs
You can fire a schedule outside its normal cadence with
POST /v1/scheduled-reports/{id}/executions.
By default it runs every active region config attached to the schedule;
pass region_config_id to scope the run to one. Manual runs do not advance
next_run_at.
Region config
A region config is one market you want to track on a given schedule:
country: the market (e.g.United States).language: the language we ask the AI platforms in.location: optional finer-grained locality (e.g.Manhattan).ai_platforms: which engines to query:chatgpt,claude,gemini,grok,perplexity,ai_overviews. Omitted, it is["chatgpt", "claude", "ai_overviews"]; any other value answers422 ai_platform_unsupported. 1 to 3 engines cost 1 credit per prompt on each run, 4 to 6 cost 2.scheduled_report_id: required. The schedule this region belongs to.source_report_idwithcopy_report_prompts: true: seeds the config with that report’s prompts in the same call, which is how a one-off report becomes a tracked market. A report with nothing to copy leaves the config paused instead of waking a schedule that would run nothing.
Region configs live under /v1/region-configs (not nested under a schedule)
because they are first-class resources you may want to:
- list across a brand for analytics,
- attach/detach independently of their parent schedule,
- or copy from a previous one when expanding to a new market.
Each schedule is capped at 20 active region configs.
Attaching, re-attaching, removing
There are three patterns:
| You want to… | Endpoint |
|---|---|
| Create a new region config under a schedule | POST /v1/region-configs with scheduled_report_id set |
| Move an existing region config to a different schedule | POST /v1/scheduled-reports/{id}/region-configs/{rc_id} |
| Remove a region from a schedule | DELETE /v1/region-configs/{rc_id} (cascades to prompts and history) |
There is intentionally no detach endpoint: the
region_configs.scheduled_report_id column is NOT NULL, so a region config
cannot exist “unlinked”. To take a region out of a schedule, delete the
region config, or move it to a different schedule with the attach endpoint.
Prompts
The leaf level. Each prompt is a single question we’ll ask every AI platform on the region config:
{
"prompt_text": "best running shoes for marathon training",
"category": "Running Shoes"
}
category is required: pick a stable free-form bucket that names the
topic the prompt is about (e.g. Running Shoes, Football Boots,
Training Apparel). It powers the per-category
breakdowns surfaced in schedule analytics, so two prompts about the same
topic should share the same category. Prompts are bulk-managed under
POST /v1/region-configs/{id}/prompts;
each region config is capped at 50 active prompts.
Prompts on a region config are soft-deleted: deleting a prompt sets
disabled=true so it stops appearing in future runs while past reports
remain unchanged. To wipe all active prompts at once and re-seed, use
DELETE /v1/region-configs/{id}/prompts.
Many prompts at once, across schedules
GET /v1/brands/{brand_id}/prompts lists every prompt the brand tracks, one
row per text, with the tracked[].id it has on each schedule and location.
PATCH /v1/brands/{brand_id}/prompts takes up to 500 of those ids, from any
schedule and location of the brand, and pauses them (disabled: true),
resumes them (disabled: false) or moves them to a category in one call.
Every id is checked first: one that is not a tracked prompt of the brand
answers 404 not_found and nothing changes. Resuming past the 50 active
prompts of a location is refused whole, and resuming reactivates a paused
location that gets prompts back. Sending the same call again is safe.
Putting it together
Setting up a brand-new weekly schedule for two markets, in one call:
curl -X POST https://api.rankprompt.com/v1/scheduled-reports \
-H "Authorization: Bearer rp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: schedule-adidas-weekly" \
-d '{
"brand_id": "{brand_id}",
"name": "Weekly tracking",
"frequency": "weekly",
"region_configs": [
{
"name": "United States",
"country": "United States",
"language": "en",
"ai_platforms": ["chatgpt", "perplexity"],
"prompts": [
{"prompt_text": "best running shoes for marathon training", "category": "Running Shoes"},
{"prompt_text": "alternatives to Nike Pegasus", "category": "Running Shoes"}
]
},
{
"name": "United Kingdom",
"country": "United Kingdom",
"language": "en",
"ai_platforms": ["chatgpt", "perplexity"],
"source_report_id": "{uk_report_id}",
"copy_report_prompts": true
}
]
}'
The same setup step by step, when you add markets over time:
# 1. Create the schedule (no regions yet, it's just the cadence)
curl -X POST https://api.rankprompt.com/v1/scheduled-reports \
-H "Authorization: Bearer rp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: schedule-adidas-weekly" \
-d '{"brand_id": "{brand_id}", "name": "Weekly tracking", "frequency": "weekly"}'
# 2. Add a US region config under it
curl -X POST https://api.rankprompt.com/v1/region-configs \
-H "Authorization: Bearer rp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: rc-adidas-us" \
-d '{
"brand_id": "{brand_id}",
"scheduled_report_id": "{schedule_id}",
"name": "United States",
"country": "United States",
"language": "en",
"ai_platforms": ["chatgpt", "perplexity"]
}'
# 3. Add a UK region config under the same schedule
curl -X POST https://api.rankprompt.com/v1/region-configs \
-H "Authorization: Bearer rp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: rc-adidas-uk" \
-d '{
"brand_id": "{brand_id}",
"scheduled_report_id": "{schedule_id}",
"name": "United Kingdom",
"country": "United Kingdom",
"language": "en",
"ai_platforms": ["chatgpt", "perplexity"]
}'
# 4. Seed prompts on each region config (category is required: use the topic)
curl -X POST https://api.rankprompt.com/v1/region-configs/{us_rc_id}/prompts \
-H "Authorization: Bearer rp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: prompts-adidas-us" \
-d '{"prompts": [
{"prompt_text": "best running shoes for marathon training", "category": "Running Shoes"},
{"prompt_text": "alternatives to Nike Pegasus", "category": "Running Shoes"}
]}'
# 5. (Optional) Run it now instead of waiting for the next tick
curl -X POST https://api.rankprompt.com/v1/scheduled-reports/{schedule_id}/executions \
-H "Authorization: Bearer rp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: run-schedule-once" \
-d '{}'
After that, every weekly tick produces two reports (one per region config)
that you can list with GET /v1/reports?scheduled_report_id={schedule_id} or
analyse in aggregate via
GET /v1/scheduled-reports/{id}/analytics.
Reading what came back
Three lenses, depending on what you want to render:
- Per-run reports:
GET /v1/reports?scheduled_report_id={schedule_id}returns one report per region config per tick, each with prompts and per-platform results inlined. - Runs:
GET /v1/scheduled-reports/{id}/runslists the schedule’s runs, newest first, each with the report it left for every region config, so a schedule with three markets shows three reports under each run. It pages withlimitandoffset. - Schedule analytics:
GET /v1/scheduled-reports/{id}/analyticsrolls every completed run into average visibility, per-prompt sparklines, and per-AI-platform appearance rates.regions[*]gives each region config its visibility in every completed run and its own platform performance, to compare markets side by side.latest_changecompares the latest run with the one before over the answers both asked (region_changesdoes it per region config), andrun_changeslists the runs that asked other prompts, AI platforms or places than the run before: a step there is not a gain or a loss. - A run in progress: while a report runs,
GET /v1/reports/{id}says where it is inbuild_phase(queued,answering,resolving,finishing) and how far inprogress(cells answered and failed out ofcells_total). Poll it untilstatusiscompletedinstead of waiting blind; both fields arenullonce it is done. - Across schedules and one-off reports:
GET /v1/brands/{brand_id}/visibility/trendsreads every run of any reports or schedules, each prompt’s trend and the competitor race. - Per-prompt history:
GET /v1/scheduled-reports/{id}/prompt-history/{region_config_prompt_id}returns one entry per run for a single prompt, perfect for time-series charts of how a question’s visibility evolves.
Lifecycle gotchas
- Deleting a brand cascades to its schedules, region configs, prompts and reports. Irreversible.
- Deleting a schedule deletes the linked reports and their prompts; the region configs are removed with it.
- Deleting a region config cascades to its prompts and historical reports for that region.
- Disabling a region config (
PATCH ... is_active=false) keeps the data but stops future ticks from running it. - Manual runs (
POST .../executions) don’t advancenext_run_at.