> For the complete documentation index, see [llms.txt](https://help.rankability.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.rankability.com/api/api-reporter-endpoints.md).

# Tracker API endpoint reference

Tracker API resources are scoped to the authenticated organization. The legacy `/reporter` route and `reporter:*` scope names remain for compatibility. An ID from another organization returns `404 not_found` rather than revealing that resource.

Prefix every route with:

```
https://app.rankability.com/api/agent/v1
```

Start with [Getting started with the Tracker API](/api/api-reporter-getting-started.md) if you have not yet validated a read-only integration.

## Project routes

| Method   | Path                     | Scope            | Purpose                                                               |
| -------- | ------------------------ | ---------------- | --------------------------------------------------------------------- |
| `GET`    | `/reporter/projects`     | `reporter:read`  | List projects                                                         |
| `POST`   | `/reporter/projects`     | `reporter:write` | Create a project                                                      |
| `GET`    | `/reporter/projects/:id` | `reporter:read`  | Read configuration, SPI, platform summary, scheduling, and latest run |
| `PATCH`  | `/reporter/projects/:id` | `reporter:write` | Update supported project settings                                     |
| `DELETE` | `/reporter/projects/:id` | `reporter:write` | Permanently delete a project                                          |

### Create a project

`POST /reporter/projects` requires `name` and a `keywords` array containing exactly one non-empty string or `{ "keyword": "...", "targetDomain": "..." }` object. One Tracker project represents exactly one durable keyword/report identity. Create separate projects for additional keywords.

Optional fields are:

* `client_id` — client UUID in the organization.
* `target_domain` and `brand_name`.
* `gbp_location_name`.
* `platforms` — defaults to Google organic, Bing, ChatGPT, Perplexity, and Gemini.
* `location`, `location_lat`, and `location_lng`.
* `grid_size` — `3x3`, `5x5`, or `7x7`; defaults to `3x3`.
* `language` — defaults to `en`.
* `frequency` — `daily`, `weekly`, or `monthly`; defaults to `daily`.
* `platform_frequencies` — platform-specific frequency map.
* `auto_track_enabled` — defaults to true; false creates benchmark tracking state.

Send `Idempotency-Key` when retrying project creation. Rankability enforces the organization's tracking-project plan allowance and validates `client_id` ownership. Creating a project does not run an immediate scan; automatic tracking schedules future protected work only when `auto_track_enabled` is true.

### Update or delete a project

`PATCH /reporter/projects/:id` can change `name`, `target_domain`, `brand_name`, `gbp_location_name`, `platforms`, `location`, `frequency`, `platform_frequencies`, and `auto_track_enabled`.

Disabling automatic tracking clears scheduling timestamps. Enabling it or changing platforms or frequencies recalculates the schedule.

Send a stable `Idempotency-Key` for retryable updates and deletes. `DELETE` permanently removes the tracking project. Treat it as an intentional destructive action; a read-only reporting connector does not need `reporter:write`.

Project detail supports `view=summary|full` and `fields=...`. The backward-compatible default is `full`. Summary omits the duplicated provenance snapshot while preserving identity, scheduling, SPI, platform measurements, current state, and latest-run information. `next_run_at` is the earliest real scheduled timestamp for recurring projects and is `null` for benchmark projects.

## Results and scan routes

| Method | Path                                   | Scope           | Purpose                                                             |
| ------ | -------------------------------------- | --------------- | ------------------------------------------------------------------- |
| `GET`  | `/reporter/projects/:id/results`       | `reporter:read` | Read grouped platform results                                       |
| `GET`  | `/reporter/projects/:id/trends`        | `reporter:read` | Read up to 90 days of terminal-run trends                           |
| `GET`  | `/reporter/projects/:id/scan-estimate` | `reporter:read` | Legacy estimate route; pooled accounts should use `/usage/estimate` |
| `POST` | `/reporter/projects/:id/scan`          | `reporter:run`  | Queue a manual scan                                                 |

### Result snapshots

`GET /reporter/projects/:id/results` supports:

* No query or `snapshot=latest_per_platform` — newest available successful result for each tracked platform or keyword.
* `snapshot=latest_run` — only the newest run.
* `run_id=RUN_ID` — one explicit historical run; this overrides the snapshot choice.
* `view=compact` — position, mention, citation, URL, state, and change fields without complete answers or provider diagnostics.
* `view=full` — the backward-compatible default with complete stored answer and evidence fields when available.

The response always identifies `snapshot.method`, `latest_run_id`, the result-source run IDs, coverage by platform, and the latest run status. The default can intentionally combine results from several runs after a partial or failed attempt.

Each platform also exposes `carried_forward_from_latest_run`. It is true when the current valid measurement came from an older project run, including when the newest run omitted the platform. `using_last_success` is narrower: it is true only when the platform's latest recorded attempt failed and the response falls back to an earlier successful result.

Traditional rows preserve rank, change, URL, and engine data. AI rows can include `answer_text`, `answer_excerpt`, brand sentiment data, detected brands, mention position, citations, provider provenance, and capture time. `snippet` remains a compatibility alias for `answer_excerpt`.

Every platform snapshot includes separate measurement and history fields. `data_state` is `not_tracked`, `no_scan`, `not_ranked`, or `measured`. `comparison_state` is `no_history` or `comparable` when a current measurement exists, and otherwise `null`. These states are never interchangeable with numeric zero, and `no_history` is never a `data_state` value.

Project detail also places those fields directly on every `platforms_detail` entry, including configured platforms with no result, so consumers do not need to infer measurement state from omission, `null`, or `false`. SPI `breakdown` categories are `null` when unmeasured, with a parallel `category_states` map; a returned numeric zero therefore means a measured zero.

### Trend semantics

`GET /trends?days=30` defaults to 30 days and caps the request at 90. It includes `complete` and `partial` terminal runs. Every point identifies `run_status` and coverage so consumers can distinguish missing work from a fully completed scan.

### Manual scans

`GET /scan-estimate` returns usage impact for the project's current platforms, location, Local Pack grid, and tracked keyword count without starting work. A scan runs every keyword on every selected platform, so impact scales with project scope. `POST /scan` returns a queued `run_id`; send a stable `Idempotency-Key` for retryable automation. It rejects archived projects with `400 invalid_operation` and returns `409 conflict` when a scan is already pending or running.

## Summary routes

| Method | Path                                              | Scope           | Purpose                                                                                       |
| ------ | ------------------------------------------------- | --------------- | --------------------------------------------------------------------------------------------- |
| `GET`  | `/reporter/summary`                               | `reporter:read` | Organization or optional client-level SPI summary                                             |
| `GET`  | `/reporter/matrix?client_id=...`                  | `reporter:read` | Bounded client keyword × platform position, mention, and citation matrix                      |
| `GET`  | `/reporter/brand-summary?client_id=...`           | `reporter:read` | Client AI mention and citation summary                                                        |
| `GET`  | `/reporter/seo-performance?client_id=...&days=28` | `reporter:read` | Client GSC and GA4 organic-search performance from the client's connected Google integrations |

`/reporter/summary` accepts an optional `client_id`. It returns project counts, explicit data/comparison states, average SPI, change from prior measurements when available, platform coverage, and top movers. `snapshot_method: "latest_per_platform"` means `average_spi` is calculated from the same current snapshot model as project detail, including valid carried-forward platform results after a partial run. `projects_with_history` counts projects with at least one comparable platform, while `projects_with_spi_delta` counts the narrower set whose immediately previous per-platform snapshot supports a complete SPI comparison. A summary with current measurements and no prior scan returns `data_state: "measured"` with `comparison_state: "no_history"`. `average_spi` is `null` when no completed measurement exists, and `spi_delta` is `null` when no comparable SPI snapshot exists.

Tracker project-list pagination includes `limit`, `requested_limit`, `offset`, `count`, `total`, and `has_more`. A compact default request can also return `limit_cap_reason: "compact_default_fields"` when its payload-safety cap applies.

`/reporter/matrix` requires `client_id`, defaults to active projects, accepts `status=active|archived|all`, optional comma-separated `platforms`, and `limit`/`offset` pagination up to 100 rows. It returns one compact row per independent keyword report with explicit measurement, comparison, URL, and freshness fields. Active selection includes legacy projects whose stored status is null.

`/reporter/brand-summary` requires `client_id`. It uses the latest available result per platform and reports projects with and without data, citation and mention rates, counts, and per-platform breakdown. It is an aggregation, not a replacement for the underlying result evidence.

`/reporter/seo-performance` requires `client_id` and accepts `days=7`, `28`, or `90`. It reuses the Google Search Console and GA4 properties already connected to that Rankability client. The response includes current and previous totals, daily trends, GSC queries and pages, submitted sitemaps, and GA4 organic landing pages. Google refresh tokens remain inside Rankability and are never returned to the caller.

## Common failures

* `400 invalid_input` — invalid create/update payload or snapshot value.
* `400 invalid_operation` — a scan was requested for an archived project.
* `403 forbidden` — the key lacks the exact read, run, or write scope.
* `403 plan_limit_exceeded` — project creation exceeds the organization's tracking allowance.
* `404 not_found` — project, client, or run is absent or outside the organization.
* `409 conflict` — a scan is already in progress.

Review [API usage, rate limits, and errors](/api/api-credits-rate-limits-and-errors.md) before adding automatic retries or scan schedules.
