# A rank tracking API for Google positions as JSON.

URL: https://serpel.app/developers/rank-tracking-api

Updated: 2026-10-10

A rank tracking API lets your code add keywords, start rank checks and read Google positions without a dashboard. Serpel’s REST API returns positions for desktop and mobile as JSON, with history, ranking URL and AI Overview status, and it uses the same projects and credits as the app. Authenticate with a bearer token that carries the `rankings:read` and `rankings:write` scopes.

## What the rank tracking API covers

- **REST and JSON:** Resource-style endpoints under `/api/v1` with a consistent `data`, `pagination` and `error` format.
- **Device and location per keyword:** Set country, language, device and a Google location code for every keyword you add.
- **Asynchronous checks:** Start a check and follow it as a job, or let scheduled monitoring run it for you.
- **History and result pages:** Read the position history of a keyword and the stored organic results of its last check.
- **Scoped tokens:** Limit a token to rank tracking, to chosen projects and to an expiry date.
- **Estimates before you spend:** Ask `POST /billing/estimate` for the credit cost of a check before you start it.

## What is a rank tracking API?

A rank tracking API returns search positions as data. Instead of opening a dashboard, your script, CI job or reporting tool asks for the positions of your keywords and gets them as JSON. Serpel’s API is a REST API under `/api/v1`. The dashboard and the CLI call the same endpoints with the same permission checks.

Whether you call it a rank tracker API, an SEO rank API or a Google rank tracking API, the flow is the same: add keywords, trigger checks, read positions. The page on [keyword rank tracking](https://serpel.app/features/rank-tracking) explains what each check records.

## Which endpoints cover rank tracking?

| Endpoint | What it does | Scope |
| --- | --- | --- |
| `POST /projects/{id}/rankings` | Adds keywords with country, language, device and location. | `rankings:write` |
| `POST /projects/{id}/rankings/run` | Starts a check for all or selected keywords and returns a job. | `rankings:write` |
| `GET /jobs/{id}` | Reports the job status: queued, running, succeeded, failed or cancelled. | `rankings:read` |
| `GET /projects/{id}/rankings` | Lists tracked keywords with latest position, change and ranking URL. | `rankings:read` |
| `GET /projects/{id}/rankings/summary` | Totals: tracked, top 3, top 10, not found and average position. | `rankings:read` |
| `GET /rank-keywords/{id}/history` | Returns the position history of one keyword. | `rankings:read` |
| `GET /rank-keywords/{id}/serp` | Returns the stored organic results of the last check. | `rankings:read` |
| `GET /locations` | Finds location codes for cities, postal codes and regions. | `rankings:read` or `projects:read` |
| `GET /projects/{id}/competitors/comparison` | Compares your positions with competitors, keyword by keyword. | `rankings:read` |

All paths start with `/api/v1`. The [REST API](https://serpel.app/developers/api) page covers the other areas of the API.

## How do rank checks run?

Checks are asynchronous. `POST /projects/{id}/rankings/run` answers with `202` and a job, and the response field `alreadyRunning` tells you when a check for the project is already in progress. Poll `GET /jobs/{id}` until the status is `succeeded`, `failed` or `cancelled`, then read the keyword list again.

Scheduled monitoring uses the same jobs. Once a project has a schedule, its keywords are checked daily, every 3 days or weekly without any API call, and every run ends with a report.

## How do you read a position?

| Field | Meaning |
| --- | --- |
| `latest.position` | The position of your domain. It is `null` when the domain was not found within the checked depth. |
| `latest.depth` | How many results the check looked at. |
| `latest.url` | The URL of your page that ranks. |
| `change` | The difference to the previous check. A positive number means the keyword moved up. |
| `latest.aiOverview` | Whether Google showed an AI Overview and whether it cites your domain. |
| `device` and `locationName` | The device and the location the keyword is checked for. |
| `searchVolume` and `cpc` | Estimates added for the keyword, `null` until they are available. |

## How does authentication work?

Send an API token as a bearer token. Create one in the dashboard under Settings, API tokens, or with `serpel tokens create`. Serpel has 18 scopes. Rank tracking needs `rankings:read` to read and `rankings:write` to add keywords and start checks. A token can be limited to specific projects and given an expiry date. Tokens begin with `vsk_` and are shown only once.

## What does the rank tracking API cost?

Reading positions is free. A check books credits per keyword from the public price list. `POST /billing/estimate` returns the cost of an operation without booking it, and a request that your balance can’t cover fails with `402` and `insufficient_credits`.

| Check | Credits per keyword | Price per keyword |
| --- | --- | --- |
| Started with `POST /projects/{id}/rankings/run`, up to top 50 | 5 | €0.05 |
| Started with `POST /projects/{id}/rankings/run`, top 100 | 9 | €0.09 |
| Scheduled run, up to top 50 | 2 | €0.02 |
| Scheduled run, top 100 | 3 | €0.03 |

Plans and credit packs are on the [pricing](https://serpel.app/pricing) page. The page on [mobile rank tracking](https://serpel.app/features/mobile-rank-tracking) shows how the device setting works.

## How does the API report errors and limits?

- Errors use one format: `{ "error": { "code", "message", "details" } }`.
- `400 validation_error` means invalid input. `401 unauthorized` means a missing or invalid token.
- `402 insufficient_credits` carries `details.available` and `details.required`.
- `403 forbidden` means a missing scope. `403 plan_limit` means a plan limit, such as the keyword limit per project, was reached.
- `429 rate_limited` carries a `Retry-After` header and `details.retryAfterSeconds`. Calls that cost credits are limited more tightly than reads.

## Your first rank check through the API

1. **Create a token** Create a token with the two rank tracking scopes, limited to one project. The secret is shown once, so store it as a secret in your CI system.

```bash
serpel tokens create --name rank-api --scope rankings:read --scope rankings:write --project <project-id>
```

2. **Poll the job** After the `rankings/run` request, poll the job until its status is `succeeded`.

```bash
curl "https://serpel.app/api/v1/jobs/$JOB_ID" \
  -H "Authorization: Bearer $SERPEL_TOKEN"
```

3. **Read the summary** The summary returns totals for the whole project in one call.

```bash
curl "https://serpel.app/api/v1/projects/$PROJECT_ID/rankings/summary" \
  -H "Authorization: Bearer $SERPEL_TOKEN"
```

## Frequently asked questions

### Is there a free rank tracking API?

Serpel’s API is part of every plan, including the free one, and reading data costs nothing. Checks cost credits at the public price list, and new accounts start with 100 credits.

### Does the API return live or stored positions?

The list endpoints return the result of the latest check that Serpel stored. To get fresh positions, start a check with `POST /projects/{id}/rankings/run` and read the list again when the job has succeeded. Each check also reports whether it came from a cache in the field `cached`.

### Can I get rankings for a city through the API?

Yes. Use `GET /locations?country=US&q=austin` to find a location code and pass it as `locationCode` when you add keywords. Without a code, the project’s default location applies, or nationwide results if the project has none.

### Can I track mobile and desktop through the API?

Yes. Pass `device` as `desktop` or `mobile` when you add a keyword. Each keyword keeps its own device, so add the keyword twice to track both.