API
Create checks and read verdicts from your own system, and track keyword positions the same way. Same credits, same answers, same endpoints the app uses — there is no separate API to fall out of step.
Base URL https://api.indexaction.com/api/v1
Authentication
Create a key in your account under API, then send it as a bearer-style header. The key is shown once at creation — only a hash is stored, so it cannot be recovered afterwards. Rate limits apply per key, so one integration can never starve another.
Authorization: Api-Key ia_live_xxxxxxxxxxxxxxxx Create a check
Duplicates and invalid lines are removed before anything is charged, and the response tells you
what was dropped. Send an Idempotency-Key and a retried
request resolves to the same check instead of charging twice.
curl https://api.indexaction.com/api/v1/checks/ \
-H "Authorization: Api-Key YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"urls": [
"https://example.com/page-1",
"https://example.com/page-2"
],
"name": "June batch"
}' Returns 201 with the check, initially queued:
{
"id": "55c79216-28fd-4c54-b813-14bb210d6fae",
"status": "queued",
"total_count": 2,
"processed_count": 0,
"credits_used": "2.00",
"input_report": { "submitted": 2, "accepted": 2, "duplicates": 0, "invalid": 0 },
"results": []
} Read the results
Poll until status is
succeeded,
failed or
canceled. Partial results are available while it runs, so
you can stream progress. A second or two between polls is plenty.
{
"status": "succeeded",
"total_count": 2,
"indexed_count": 1,
"not_indexed_count": 1,
"error_count": 0,
"indexed_pct": 50.0,
"credits_used": "2.00",
"credits_refunded": "0.00",
"results": [
{ "url": "https://example.com/page-1", "status": "indexed",
"note": "Found in Google",
"matches": [{ "link": "https://example.com/page-1", "title": "Page 1" }] },
{ "url": "https://example.com/page-2", "status": "not_indexed",
"note": "Google returned no result", "matches": [] }
]
} Verdicts
Three values, and the third one matters. Most tools collapse a failed check into “not indexed”, which sends you chasing a problem that may not exist.
indexed Google returned the page — at the exact URL, or the same page under its canonical URL.
not_indexed Google returned no result in any query form we try. Established by an individual query, not inferred.
error We could not determine it — a timeout or an upstream failure. Treat as unknown, never as missing. This credit is refunded.
indexed_pct excludes errors from its denominator: a run
where half the checks failed should not report a halved index rate.
Rank tracking
A rank project is a domain, its keywords, and where to look: a market
(gl country +
hl language), a device, and a depth of 10, 30 or 100.
One check scans every keyword on every device the project tracks.
Cost is one credit per results page, per keyword, per device: top 10 is 1 page, top 30 is 3, top 100 is 10. The full depth is charged when the check starts. A scan stops as soon as it has found your domain and every competitor, and the pages it did not need are refunded when it finishes — as are keywords whose lookup failed.
Create a project
curl https://api.indexaction.com/api/v1/rank/projects/ \
-H "Authorization: Api-Key YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Example",
"domain": "example.com",
"keywords": ["bulk index checker", "check if url is indexed"],
"gl": "us",
"hl": "en",
"devices": "desktop",
"depth": 30,
"competitors": ["rival.com"],
"schedule_enabled": true,
"schedule_hour": 7,
"timezone_name": "UTC"
}' domain may be a URL; it is stored as the bare host, and
subdomains count as the same site. devices is
desktop, mobile or
both. Nothing is charged until a check runs; the response
says what one will cost:
{
"id": "9f559ea8-2ad1-41f4-953f-0d3131b7d432",
"domain": "example.com",
"depth": 30,
"keyword_count": 2,
"cost_per_run": "6.00",
"schedule_enabled": true,
"next_run_at": "2026-09-18T07:00:00Z",
"last_run": null,
...
} Run a check, then read positions
curl -X POST https://api.indexaction.com/api/v1/rank/projects/PROJECT_ID/run/ \
-H "Authorization: Api-Key YOUR_KEY" \
-H "Idempotency-Key: $(uuidgen)"
# poll until status is succeeded, failed or canceled
curl https://api.indexaction.com/api/v1/rank/runs/RUN_ID/ -H "Authorization: Api-Key YOUR_KEY"
# then read each keyword's latest position per device
curl https://api.indexaction.com/api/v1/rank/projects/PROJECT_ID/keywords/ -H "Authorization: Api-Key YOUR_KEY" [
{
"id": "10a5e2cf-15ce-4caa-a79b-be8ed4874043",
"keyword": "bulk index checker",
"latest": {
"desktop": {
"status": "ranked",
"position": 12,
"previous_position": 15,
"has_previous": true,
"best_position": 9,
"url": "https://example.com/bulk-index-checker",
"competitors": { "rival.com": 4 },
"previous_competitors": { "rival.com": 6 },
"checked_at": "2026-09-18T07:00:41+00:00"
}
}
}
] -
statusisranked(with aposition) ornot_found— not in the scanned depth, sopositionisnull. Positions count organic results only, across pages. -
A lookup that fails never replaces a known position. The keyword keeps its last answer and
gains
last_error_at; the failed check is refunded. -
has_previousis false on a keyword's first check, so there is no change to report yet. -
For every recorded position, use
GET /rank/keywords/{id}/history/?days=90.
Plan limits
Accounts that have never bought credits can track one project of up to 10 keywords in the top
10, without competitors. Any credit pack lifts that. GET /rank/meta/
returns the limits that apply to the calling account, and a request over them is refused with
a code saying which one — before anything is charged.
Endpoints
Index checks
| Method | Path | Purpose |
|---|---|---|
| POST | /checks/ | Create a check. Up to 1,000 URLs. |
| GET | /checks/{id}/ | Status, counts, and per-URL verdicts. |
| GET | /checks/ | Paginated history. Filter by status, project, date. |
| POST | /checks/{id}/cancel/ | Stop a running check; unchecked URLs are refunded. |
| POST | /checks/{id}/rerun/ | Re-run the same URL list. |
| GET | /checks/{id}/diff/ | Newly indexed and dropped-out URLs vs the previous check. |
| GET | /checks/{id}/export/ | Download CSV or XLSX. ?format=csv|xlsx&verdict=… |
| DELETE | /checks/{id}/ | Remove a check from history. Credits are not affected. |
Projects and schedules
| Method | Path | Purpose |
|---|---|---|
| GET | /projects/ | Saved URL lists. Full CRUD at /projects/{id}/. |
| GET · PUT | /projects/{id}/urls/ | Read or replace a project's URL list. |
| POST | /projects/{id}/check/ | Check the project's saved list now. |
| GET | /projects/{id}/runs/ | The project's checks, newest first. |
| GET | /projects/{id}/trend/ | Index rate at each successful check. |
| GET | /schedules/ | Automatic re-checks. Full CRUD; one per project. |
| POST | /schedules/{id}/run-now/ | Run a schedule's check immediately. |
Rank tracking
| Method | Path | Purpose |
|---|---|---|
| GET | /rank/projects/ | Tracked domains with stats. Full CRUD at /rank/projects/{id}/. |
| GET · POST | /rank/projects/{id}/keywords/ | List keywords with their latest positions, or add more. |
| POST | /rank/projects/{id}/keywords/remove/ | Remove keywords and their history. Body: {"ids": [...]} |
| POST | /rank/projects/{id}/run/ | Check rankings now. Accepts Idempotency-Key. |
| GET | /rank/projects/{id}/runs/ | The project's rank checks, newest first. |
| GET | /rank/projects/{id}/export/ | Current positions as CSV, one row per keyword and device. |
| GET | /rank/runs/{id}/ | Status and counts of one rank check. |
| POST | /rank/runs/{id}/cancel/ | Stop a running rank check; unscanned pages are refunded. |
| GET | /rank/keywords/{id}/history/ | Every position recorded. ?days=30|90|365 |
| GET | /rank/meta/ | This account's limits and price per page. |
Account
| Method | Path | Purpose |
|---|---|---|
| GET | /dashboard/ | Balance and aggregate totals. |
Errors
Every error carries a stable machine-readable code, so
you never have to match on human-readable text.
{ "code": "insufficient_credits",
"detail": "You do not have enough credits for this check.",
"required": "1000.00", "balance": "240.00", "shortfall": "760.00" } 402 insufficient_credits— top up and retry.409 active_run_limit— wait for a check to finish.503 provider_unavailable— nothing was charged; retry shortly.503 deep_scan_unavailable— top 30/100 rank checks are briefly unavailable; top 10 still works. Nothing was charged.400 plan_depth,too_many_keywords,too_many_projects,too_many_competitors— over this account's rank limits; the body carrieslimitandfree_tier.400 invalid_domain,invalid_locale,no_keywords— fix the request; nothing was charged.400 validation_error— seeerrorsfor field detail.401 authentication_failed— the key is wrong or revoked.429 throttled— slow down; limits are per key.
An OpenAPI schema is served at
https://api.indexaction.com/api/schema/, with a
browsable reference at /api/docs/.