Skip to main content

Usage & quota

Your Ranktracker plan sets limits on how much you can track: how many keywords you can have active, and how many data rows those keywords consume. Every tracked keyword counts against these limits, so before you add keywords in bulk it pays to check what you have left.

This guide covers the one endpoint you need for that: GET /v1/account/usage — how to read it, how the quota model works, and what happens when you go over.

:::tip New to the API? Start with the Quickstart and Authentication guides. This guide assumes you already have an API key and can make an authenticated request. :::

Read your usage

GET /v1/account/usage returns your plan's current usage and limits. It takes no parameters — it always reports on the account that owns the API key.

curl https://api.ranktracker.com/v1/account/usage \
-H "Authorization: tkn_usr_your_api_key_here"
import requests

resp = requests.get(
"https://api.ranktracker.com/v1/account/usage",
headers={"Authorization": "tkn_usr_your_api_key_here"},
)
resp.raise_for_status()
usage = resp.json()["data"]["attributes"]
print("Keywords remaining:", usage["keywords"]["remaining"])
const resp = await fetch("https://api.ranktracker.com/v1/account/usage", {
headers: { Authorization: "tkn_usr_your_api_key_here" },
});
const { data } = await resp.json();
console.log("Keywords remaining:", data.attributes.keywords.remaining);

Response

The response is a single JSON:API resource. The quota numbers live under data.attributes:

{
"data": {
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"type": "usage",
"attributes": {
"apiEnabled": true,
"keywords": {
"usage": 842,
"limit": 1000,
"remaining": 158
},
"dataRows": {
"usage": 4210,
"limit": 5000,
"remaining": 790
},
"onDemand": {
"usage": 12,
"limit": 50,
"remaining": 38
},
"serpAnalyser": {
"usage": 3,
"limit": 25,
"remaining": 22
}
}
}
}

What the fields mean

FieldMeaning
apiEnabledWhether API access is enabled on your plan. If false, other endpoints return 403.
keywordsTracked-keyword quota — see below.
dataRowsData-row quota — see below.
onDemandOn-demand ranking-check credits.
serpAnalyserSERP Analyser credits.

Each quota object has the same three integer fields:

  • usage — how much you've consumed.
  • limit — the ceiling your plan allows.
  • remaining — how much headroom is left (limit - usage).
note

Keyword credits are rounded to whole numbers, so usage, limit and remaining are always integers.

Keywords vs. data rows

These are two separate limits, and a keyword create must satisfy both:

  • Keywords counts each tracked keyword you have active.
  • Data rows counts the underlying tracking rows those keywords generate. A single keyword phrase tracked across more than one search engine, location, language, or device produces one data row per combination.

Because creating keywords tracks the cartesian product of words × search_engines, one request can consume many data rows. Ten phrases across three search-engine configurations is 30 data rows, not 10. Keep that multiplier in mind when you size a bulk import against your dataRows remaining.

Check quota before you track

Read remaining for both keywords and dataRows and compare against what your create request will consume before you send it. A create request either fits entirely or is rejected entirely — it does not partially apply — so pre-checking avoids a wasted round trip.

import requests

BASE = "https://api.ranktracker.com/v1"
HEADERS = {"Authorization": "tkn_usr_your_api_key_here"}

words = ["running shoes", "trail shoes", "trainers"]
search_engines = [
{"name": "google", "location": "United States", "language": "en", "device": "desktop"},
{"name": "google", "location": "United States", "language": "en", "device": "mobile"},
]
# Tracking the cartesian product of words × search_engines adds one keyword
# (and one data row) per combination, so a create consumes BOTH keyword credits
# and data rows — check both before you send it.
needed = len(words) * len(search_engines)

usage = requests.get(f"{BASE}/account/usage", headers=HEADERS).json()["data"]["attributes"]
if usage["keywords"]["remaining"] < needed or usage["dataRows"]["remaining"] < needed:
raise SystemExit(
f"Need {needed} keyword credits and {needed} data rows; have "
f"{usage['keywords']['remaining']} and {usage['dataRows']['remaining']} remaining."
)

resp = requests.post(
f"{BASE}/domains/DOMAIN_UUID/keywords",
headers=HEADERS,
json={"frequency": "daily", "words": words, "search_engines": search_engines},
)
resp.raise_for_status()
print("Tracked", len(resp.json()["data"]), "keywords")
note

The usage endpoint reflects the state at the moment you call it. If several processes add keywords concurrently, treat the pre-check as a guard, not a guarantee — always be ready to handle a 402 on the create itself (see below).

What happens when you exceed it

If a keyword create would push you over your keyword or data-row limit, the API rejects it with HTTP 402 Payment Required and tracks nothing — the request is all-or-nothing, so no partial set of keywords is created.

curl -i -X POST https://api.ranktracker.com/v1/domains/DOMAIN_UUID/keywords \
-H "Authorization: tkn_usr_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"frequency": "daily",
"words": ["running shoes"],
"search_engines": [
{ "name": "google", "location": "United States", "language": "en", "device": "desktop" }
]
}'

A 402 uses the standard JSON:API error envelope:

{
"errors": [
{
"code": "over_quota",
"status": 402,
"detail": "Adding these keywords would exceed your plan's quota."
}
]
}

To recover, free up room or raise your ceiling, then retry:

  • Stop tracking keywords you no longer need. Pause a keyword with a PATCH that sets tracked to false, or remove it entirely with a DELETE. Re-read GET /v1/account/usage to confirm remaining has recovered.
  • Upgrade your plan in your Ranktracker account to raise limit.
warning

402 is about plan quota, not authentication or throttling. Retrying the same request without freeing quota will just fail again. Don't confuse it with a 503 (a throttled request — retry those with backoff, covered in Errors & rate limits) or a 403 (API access disabled, indicated by apiEnabled: false here).