> 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-researcher.md).

# Researcher API

Use the Researcher API to start keyword-research jobs, poll their results, and read projects that have already been saved in Researcher. API jobs and saved projects are related but separate resources.

## Scopes and routes

| Method | Path                       | Scope             | Purpose                               |
| ------ | -------------------------- | ----------------- | ------------------------------------- |
| `POST` | `/researcher/jobs`         | `researcher:run`  | Start a research job                  |
| `GET`  | `/researcher/jobs`         | `researcher:read` | List research jobs                    |
| `GET`  | `/researcher/jobs/:job_id` | `researcher:read` | Poll a job and read its result        |
| `GET`  | `/researcher/projects`     | `researcher:read` | List saved Researcher projects        |
| `GET`  | `/researcher/projects/:id` | `researcher:read` | Read a saved project and its keywords |

Prefix every path with `https://app.rankability.com/api/agent/v1`.

## Start a research job

```bash
curl -X POST https://app.rankability.com/api/agent/v1/researcher/jobs \
  -H "Authorization: Bearer rk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: research-acme-2026-08-01" \
  -d '{
    "topics": ["commercial roofing st louis"],
    "country": "us",
    "client_id": "CLIENT_UUID",
    "mode": "discover"
  }'
```

### Request fields

| Field                  | Required | Behavior                                                                                          |
| ---------------------- | -------- | ------------------------------------------------------------------------------------------------- |
| `topics`               | Yes      | Array of 1–20 non-empty seed topics                                                               |
| `country`              | No       | Two-to-five-character country code; defaults to `us`                                              |
| `location`             | No       | More specific geographic context                                                                  |
| `client_id`            | No       | Must belong to the authenticated organization                                                     |
| `business_description` | No       | Business context; Rankability derives a fallback from client knowledge or topics                  |
| `competitor_domains`   | No       | Domains used as research context                                                                  |
| `target_audience`      | No       | Audience context                                                                                  |
| `content_goals`        | No       | Intended content outcome                                                                          |
| `include_gsc`          | No       | Requests connected Search Console context when available                                          |
| `use_knowledge_base`   | No       | Includes client knowledge; defaults to true when `client_id` is supplied and the field is omitted |
| `mode`                 | No       | `discover`, `trending`, `reddit`, `youtube`, or `ecommerce`; defaults to `discover`               |
| `refresh`              | No       | Bypasses a valid cached result and starts paid fresh research                                     |

Rankability also applies organization and client topic exclusions to the research run.

## Usage, cache, and failure behavior

| Mode        |    Current non-cached impact |
| ----------- | ---------------------------: |
| `discover`  | Standard pooled-usage impact |
| `trending`  | Standard pooled-usage impact |
| `reddit`    | Standard pooled-usage impact |
| `youtube`   | Standard pooled-usage impact |
| `ecommerce` | Standard pooled-usage impact |

A valid cached result has no additional pooled-usage impact and can be reused for up to seven days. It returns HTTP `200`, `status: "completed"`, `cached: true`, and `usage_impact.level: "none"`.

A fresh job returns HTTP `201`, `status: "pending"`, and `usage_impact`. If the job later fails without usable output, its pending usage is released.

Setting `refresh: true` deliberately bypasses the cache and can create new usage. Send a stable `Idempotency-Key` when retrying the same create request.

## Poll the job

```bash
curl https://app.rankability.com/api/agent/v1/researcher/jobs/JOB_ID \
  -H "Authorization: Bearer rk_live_YOUR_KEY"
```

Poll every 5–10 seconds with backoff. Treat these as distinct states:

* `pending` — accepted and waiting to run.
* `processing` — research is running.
* `completed` — `results` contains the keyword-research payload.
* `empty` — the run completed but filtering produced no usable keywords.
* `failed` — no usable result; inspect `error`.

The `progress.stage` and `progress.detail` fields provide current progress. Do not treat a null `results` field on an in-progress job as a failed search.

## List jobs or saved projects

`GET /researcher/jobs` accepts `client_id`, `limit`, and `offset`. The list contains summaries, not each job's complete result.

`GET /researcher/projects` lists projects saved through Researcher. `GET /researcher/projects/:id` adds the project's saved keyword rows, including volume, difficulty, CPC, intent, opportunity score, cluster, rank and GSC fields when available, status, priority, and next action.

Creating an API research job does not automatically create a saved Researcher project. Use the job result unless your workflow separately saves or manages a project through a supported Rankability workflow.

## Common failures

* `400 invalid_input` — fields failed validation or `job_id` is malformed.
* `429 usage_limit_reached` — a pooled on-demand window has reached its current limit.
* `404 not_found` — the client, job, or project is outside the organization or does not exist.
* `429 rate_limit_exceeded` — the API request limit or Researcher concurrency limit was reached.
* `500 internal_error` — the system could not record or queue the job safely.

See [API usage, rate limits, and errors](/api/api-credits-rate-limits-and-errors.md) before implementing retries. For workflow selection, return to [API use cases and integration patterns](/api/api-use-cases.md).
