ENRU
Open the bot

Google indexing API reference

Everything the bot does, over HTTP. Send URLs when a page goes live, poll the task, read what was accepted and what was filtered. Same balance, same checks, $0.01 per accepted URL.

Quick start

  1. Get a key. Open @IndexForgeBot and press 🔑 API. The key is shown once, so save it.
  2. Send URLs. POST /v1/submit with a JSON array of up to 10,000 URLs. You get a task id right away.
  3. Poll the task. GET /v1/tasks/{id} every 10 seconds or so, until the status is done, partial or failed.
  4. Read the result. Accepted, rejected with reasons, charged and refunded, all in one object.
api.indexforge.help
$ curl -X POST https://api.indexforge.help/v1/submit \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls": [
        "https://site.com/page-1",
        "https://site.com/page-2"]}'
202 Accepted · 184 ms # 202 · task created
{ "ok": true,
  "task": { "id": "3f9c2a7d1b6e4c80",
            "status": "queued", "urls": 2 } }

Base URL and authentication

All requests go to https://api.indexforge.help. Bodies and responses are JSON in UTF-8, and every response has an ok field.

Pass your key in either header:

Authorization: Bearer YOUR_KEY
X-API-Key: YOUR_KEY
  • The key is issued in the bot with the 🔑 API button and shown once. Store it like a password.
  • Generating a new key immediately disables the old one. Do that if a key leaks.
  • The API and the bot share one balance: top up in the bot, spend from either.

POST /v1/submit

Creates a task: checks the URLs the way Googlebot sees them, then sends the ones that pass for indexing.

FieldTypeDescription
urlsarray, requiredUp to 10,000 http(s) URLs. Duplicates and non-http strings are dropped.
checkbool, default trueRun the precheck. With false the check is skipped and every URL is charged.
{ "urls": ["https://site.com/page-1", "https://site.com/page-2"], "check": true }

Response 202 Accepted with the new task:

{ "ok": true,
  "task": { "id": "3f9c2a7d1b6e4c80", "status": "queued",
            "created": 1760263200, "urls": 2 } }
How credits work here

With check: true you need at least 1 credit to start. After the check, credits are reserved only for URLs that passed. Accepted URLs are charged, the rest are refunded automatically. With check: false your balance must cover every URL in the request. The request body is limited to 5 MB.

GET /v1/tasks/{id}

Status and counters for one task. Tasks are visible only to the key's owner.

FieldDescription
idTask id
statusqueued, checking, submitting, done, partial or failed
created · finishedUnix timestamps. finished appears when the task ends
urlsURLs in the task after deduplication
checkedURLs checked
rejectedURLs filtered out by the check
rejected_urlsFiltered URLs grouped by reason, up to 200 per reason
acceptedURLs accepted for indexing
charged · refundedCredits charged and returned
errorShort code when something went wrong, see statuses
{ "ok": true, "task": {
  "id": "3f9c2a7d1b6e4c80", "status": "done",
  "created": 1760263200, "finished": 1760263295,
  "urls": 3, "checked": 3, "rejected": 1,
  "rejected_urls": { "404": ["https://site.com/old"] },
  "accepted": 2, "charged": 2, "refunded": 0 } }

Reasons in rejected_urls:

KeyMeaning
404The page returned 404 or 410
4xxAnother client error, such as 401 or 403
5xxServer error
redirectThe URL redirects. Send the final address instead
noindexnoindex in meta robots, meta googlebot or the X-Robots-Tag header
robotsBlocked for Googlebot in robots.txt
canonicalThe canonical points to another URL
errorThe page didn't open: timeout, DNS or connection error, invalid URL

GET /v1/tasks

Your recent tasks, newest first. Optional limit from 1 to 100, default 20.

GET /v1/tasks?limit=20

{ "ok": true, "tasks": [ { "id": "3f9c2a7d1b6e4c80", "status": "done", … }, … ] }

GET /v1/balance

Credits left on the account and the current price.

FieldDescription
balanceCredits on the account. One credit is one URL
unlimitedtrue for accounts without a balance limit, then balance is null
price_per_url_usdPrice of one URL in US dollars
{ "ok": true, "balance": 1250, "unlimited": false, "price_per_url_usd": 0.01 }

Task statuses

queuedCreated, waiting its turn.
checkingEach URL is fetched like Googlebot and filtered.
submittingURLs that passed are being sent.
doneAll URLs that passed were accepted.

A finished task ends in one of three states:

  • done: everything that passed the check was accepted. If nothing passed, the task is also done with accepted: 0 and nothing charged.
  • partial: some URLs were accepted, credits for the rest were refunded.
  • failed: nothing was sent and reserved credits were refunded.

The error field explains a partial or failed result:

errorMeaning
insufficient_creditsNot enough credits for the URLs that passed the check
service_unavailableSubmission failed temporarily. Unaccepted credits were refunded, try again later
restartedThe task was interrupted by a service restart. Reserved credits are returned
internal_errorUnexpected error on our side

Errors

Errors come back with an HTTP status and a JSON body, so your code can tell a bad request from an empty balance:

{ "ok": false, "error": "insufficient_credits", "message": "Balance is 0. Top up in the bot." }
HTTPerrorWhen
400bad_jsonThe body isn't valid JSON
400no_urlsurls is missing, empty or has no valid http(s) URLs
400too_many_urlsMore than 10,000 URLs in one request
401unauthorizedThe key is missing, wrong or was replaced by a new one
402insufficient_creditsBalance is 0, or with check: false it doesn't cover all URLs
403forbiddenAccess to the API is closed for this account
404not_foundUnknown endpoint, or a task that doesn't exist or isn't yours
413too_largeThe request body is over 5 MB
429rate_limitedMore than 60 requests per minute
429too_many_tasks3 of your tasks are already running
500internal_errorUnexpected error on our side. Retry a bit later

Limits

60requests per minute
3tasks running at once
10 000URLs per request
5 MBrequest body

Indexing usually takes 1–3 days after a task finishes. Price: $0.01 per accepted URL, the same as in the bot.

API questions

Is this the official Google Indexing API?

No. It's our own API that runs the same checks and submission as the bot, for any kind of page. Google's own Indexing API is officially meant for job posting and livestream pages. Our guide on the Indexing API vs indexing services explains the difference.

Do I need a separate balance for the API?

No. The API and the bot share one balance. Top up in the bot and use the credits from either.

Do rejected URLs cost anything?

No. They are listed in rejected_urls by reason and never charged, unless you send the task with check: false.

How often should I poll a task?

Every 10 seconds is plenty. Large tasks take longer to check, and polling more often only uses up your 60 requests per minute.

I lost my key. What now?

Press 🔑 API in the bot and generate a new key. The old one stops working at that moment.