RankParse

IndexNow

Tell Bing, Yandex, Seznam, Naver and other IndexNow search engines about new, changed or deleted URLs the moment they change.

POST/v1/indexnow1 credit (refunded on failure)API key

IndexNow is an open protocol for notifying search engines that a URL changed. One submission from RankParse goes to api.indexnow.org, which shares it with every participating engine (Bing, Yandex, Seznam, Naver and others). RankParse submits to IndexNow only; it does not submit to any other search engine.

Two routes make up the flow: a free one that gives you a key for a host, and a 1 credit one that submits URLs.

How it works

Add the website

The host you submit must be one of your RankParse websites, or a subdomain of one. Add it in the dashboard under Sites with Add website. Submissions for any other host fail with indexnow_host_not_a_website.

Generate a key

Call POST /v1/indexnow/key?domain=example.com. You get back a key and the exact URL where it must be hosted. The call is free and returns the same key every time for the same host.

Host the key file

Publish a UTF-8 text file containing exactly the key at the root of the site, at the key_location from the previous step: https://example.com/<key>.txt. This proves to search engines that you control the host.

Submit URLs

Call POST /v1/indexnow with up to 1000 URLs from that host. On the first submission (and then at most once a day) RankParse fetches the key file to check it before sending.

POST /v1/indexnow/key

POST/v1/indexnow/keyFreeAPI key

Returns the IndexNow key for a host, creating it on first use. The key is unique to your workspace and host, and it is never rotated, so a key file you have already published stays valid.

Parameters

ParameterTypeRequiredDescription
domainquery stringYesThe host to get a key for, for example example.com or www.example.com. A full URL is accepted and reduced to its hostname. Hosts are lowercased

example.com and www.example.com are different hosts and get different keys. Provision the key for the exact host that appears in the URLs you will submit.

Example

curl -X POST "https://api.rankparse.com/v1/indexnow/key?domain=example.com" \
  -H "X-API-Key: rp_your_key"
import requests

res = requests.post(
    "https://api.rankparse.com/v1/indexnow/key",
    headers={"X-API-Key": "rp_your_key"},
    params={"domain": "example.com"},
)
info = res.json()
print(res.status_code, info["key_location"])
const res = await fetch("https://api.rankparse.com/v1/indexnow/key?domain=example.com", {
  method: "POST",
  headers: { "X-API-Key": "rp_your_key" },
});
const info = await res.json();
console.log(res.status, info.key_location);

Response

201 Created the first time, 200 OK on every later call for the same host. The body is a plain object, not wrapped in the usual data envelope.

{
  "host": "example.com",
  "key": "3f9a1c7e2b8d4e6f9a0b1c2d3e4f5a6b",
  "key_location": "https://example.com/3f9a1c7e2b8d4e6f9a0b1c2d3e4f5a6b.txt",
  "verified": false,
  "instructions": "Host a UTF-8 text file containing exactly the key at https://example.com/3f9a1c7e2b8d4e6f9a0b1c2d3e4f5a6b.txt, then submit URLs with POST /v1/indexnow."
}

Response fields

FieldTypeDescription
hoststringThe normalized host
keystringThe key, 32 lowercase hexadecimal characters. Treat it as a per-host value; only you can retrieve it
key_locationstringThe URL where the key file must be hosted: https://<host>/<key>.txt
verifiedbooleantrue when RankParse has confirmed the hosted key file within the last 24 hours
instructionsstringA one-line summary of the hosting step

The key file contents are the key and nothing else. Leading and trailing whitespace, such as a final newline, is ignored when RankParse checks it.

POST /v1/indexnow

POST/v1/indexnow1 credit (refunded on failure)API key

Submits a batch of URLs from one host to IndexNow.

Body parameters

Send JSON with Content-Type: application/json.

FieldTypeRequiredDescription
urlsstring[]Yes1 to 1000 absolute public http or https URLs. All must have the same host. No explicit ports

Rules for urls:

  • Every URL must be a valid public http(s) URL. Private or reserved addresses, URLs with credentials (user:pass@), URLs with a #fragment, and URLs with leading or trailing whitespace are rejected.
  • Every URL must use the default port. https://example.com:8443/a is rejected because IndexNow keys are verified at the default port.
  • Every URL must have exactly the same hostname. https://example.com/a and https://www.example.com/b in one call fail with indexnow_host_mismatch. Make one call per host.
  • URLs are normalized (for example the host is lowercased) before they are sent.
  • Submit URLs that are new, changed or deleted. IndexNow is a change signal, not a way to re-submit unchanged pages.

Example

curl -X POST "https://api.rankparse.com/v1/indexnow" \
  -H "X-API-Key: rp_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/blog/new-post",
      "https://example.com/pricing"
    ]
  }'
import requests

res = requests.post(
    "https://api.rankparse.com/v1/indexnow",
    headers={"X-API-Key": "rp_your_key"},
    json={
        "urls": [
            "https://example.com/blog/new-post",
            "https://example.com/pricing",
        ]
    },
)
print(res.status_code, res.json())
const res = await fetch("https://api.rankparse.com/v1/indexnow", {
  method: "POST",
  headers: {
    "X-API-Key": "rp_your_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    urls: [
      "https://example.com/blog/new-post",
      "https://example.com/pricing",
    ],
  }),
});
console.log(res.status, await res.json());

Response

{
  "data": {
    "host": "example.com",
    "url_count": 2,
    "key_location": "https://example.com/3f9a1c7e2b8d4e6f9a0b1c2d3e4f5a6b.txt",
    "status": "accepted"
  },
  "credits_used": 1,
  "credits_remaining": 998
}

Response fields

FieldTypeDescription
data.hoststringThe host that was submitted
data.url_countintegerNumber of URLs sent
data.key_locationstringWhere the key file was verified
data.statusstringaccepted when IndexNow accepted the submission (HTTP 200 or 202)
credits_usedintegerAlways 1 on success
credits_remainingintegerYour balance after the call

accepted means IndexNow accepted the notification. It does not mean any engine has crawled or indexed the pages yet.

Behavior and limits

  • Cost: 1 credit per call, whatever the number of URLs (up to 1000). Any failed call is refunded automatically, including validation errors and upstream failures. See Credits.
  • Order of checks: body and URL validation, then website ownership, then key lookup, then key file verification, then the upstream submission.
  • Key file verification: RankParse requests https://<host>/<key>.txt with a 30 second timeout and requires an HTTP 200 whose body (trimmed) equals the key. The file must be small; anything over 4 KB is treated as not a key file. A successful check is cached for 24 hours, so steady-state submissions skip it. If IndexNow later rejects the key (indexnow_key_rejected), the cache is cleared and the next submission checks the file again.
  • Subdomains: a host that is a subdomain of one of your websites is accepted (blog.example.com for a website example.com). Generate the key for the subdomain host itself.
  • Rate limit: the shared 60 requests per minute per key. IndexNow applies its own limits upstream and can answer with indexnow_rate_limited; submit changes in batches instead of one URL per call.

Approval inbox for agents

If your workspace uses the approval inbox, a call made by an AI agent does not submit immediately. A call is agent-origin when it uses an API key and carries the header X-RankParse-Client: mcp, which is what the RankParse API-key MCP server sends for submit_indexnow_urls. Calls from your own code without that header, and RapidAPI calls, are never held for approval.

For an agent-origin call in such a workspace:

SituationResponse
The website's agent policy does not allow automatic submission202 with data.status set to awaiting_approval, plus data.proposal_id, data.review_url and a message. credits_used is 0 and nothing is submitted until you approve it in RankParse
You set the policy for this website to automaticThe submission runs now and returns the normal 200 accepted response with an added data.proposal_id. The 1 credit is charged once
An automatic run is queued for the next hourly retry, or the same proposal was already approved202 with data.status set to approved and a message. It is not proposed again
An automatic run failsThe error status and code from the table below, with proposal_id added to the body. The credit is refunded
{
  "data": {
    "host": "example.com",
    "url_count": 2,
    "status": "awaiting_approval",
    "proposal_id": "prop_abc123",
    "review_url": "https://rankparse.com/dashboard/sites/site_abc123/today?proposal=prop_abc123"
  },
  "credits_used": 0,
  "credits_remaining": 998,
  "message": "Waiting for the user's approval in RankParse: ..."
}

Show the review_url to the person who must approve. Track the outcome with proposals. Agents that should always go through the inbox can call propose_indexnow_submit (below) instead.

Errors

All errors use the standard shape { "error", "code", "message" }. See Error codes. Failed submissions are refunded.

StatusCodeMeaning and fix
400invalid_domainPOST /v1/indexnow/key needs a valid domain
400indexnow_invalid_urlBody is not JSON, urls is missing or empty, an entry is not a string or not a valid public http(s) URL, or a URL has an explicit port
400indexnow_too_many_urlsMore than 1000 URLs in one call
400indexnow_host_mismatchThe URLs do not all share one host. Make one call per host
400indexnow_host_not_a_websiteThe host is not one of your RankParse websites (or a subdomain of one). Add it under Dashboard, Sites
400indexnow_key_not_foundNo key exists for this host. Call POST /v1/indexnow/key first
400indexnow_key_not_verifiedThe key file at key_location is missing, not HTTP 200, or does not contain exactly the key. Host it, then retry
400indexnow_invalid_requestIndexNow rejected the submission as malformed
401invalid_api_keyMissing, invalid or revoked API key
402insufficient_creditsNot enough credits. Nothing was charged
402spend_cap_reachedYour monthly spend cap was reached. Nothing was charged
403capability_missingYour workspace role cannot make this call
403indexnow_key_rejectedIndexNow rejected the key. Confirm the key file is still hosted at its location, then retry
422indexnow_url_mismatchIndexNow rejected the URLs: they do not belong to the submitted host, or the key does not match
429rate_limitedMore than 60 requests per minute for this key
429indexnow_rate_limitedIndexNow's rate limit was reached. Slow down and retry later
503indexnow_unavailableIndexNow is unreachable or returned an unexpected status. Retry later

MCP tools

ToolEndpointsPurpose
provision_indexnow_keyAPI-key MCPGet or create the key for a host (0 credits). Tells the agent to ask the user to host the file
submit_indexnow_urlsAPI-key MCPSubmit up to 1000 URLs on one host (1 credit, refunded on failure). In an approval-inbox workspace it returns a pending proposal instead
propose_indexnow_submitAPI-key MCP and secure OAuth connectorAsk the user to approve a submission. Always goes through the inbox. 0 credits to propose, 1 credit only when it runs

provision_indexnow_key and submit_indexnow_urls are not available on the secure OAuth connector, which can only propose. See MCP Server.

On this page