1. Basics
- Base URL:
https://indexerpal.com/api/v1. Machine-readable: OpenAPI 3.1. - Authentication:
Authorization: Bearer ipk_...(an API key) or an OAuth access token. See authentication. - JSON in and out,
snake_casefields, timestamps in ISO 8601 UTC, money in cents. Unknown fields may appear: ignore them. - Lists take
limitandoffset, orpageandper_page. - CORS is open: browsers can call the API with a bearer token.
GET /api/v1withAccept: application/jsonlists every endpoint. Without that header, and where x402 is on, the same URL returns402and the price of the basic pack.GET /api/v1/healthreports status.
2. Account
The account behind the credential.
Get account
GET /api/v1/account
The account behind this credential: credit balance, whether it can index yet (it needs one paid order), this credential's scopes, today's usage and the limits.
Any credential · MCP tool get_account.
Parameters
No parameters.
Example
curl "https://indexerpal.com/api/v1/account" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
object | "account" | |
id | string | |
email | string | |
name | string | |
credits | integer | |
paid | boolean | At least one paid order. Indexing needs it; reading and buying don't. |
credential | object | |
usage_today | object | |
limits | object | |
dashboard_url | string |
3. Pricing
Public: no credential needed (with one, the estimate also checks your balance).
Get pricing
GET /api/v1/pricing
Credit packs and prices (one-time payments in US dollars, credits never expire), what each action costs in credits, and when URLs are checked in Google.
No credential needed · MCP tool get_pricing.
Parameters
No parameters.
Example
curl "https://indexerpal.com/api/v1/pricing"
Response (200)
| Field | Type | Description |
|---|---|---|
object | "pricing" | |
currency | string | |
packs | array of object | |
costs | object | |
check_days | object | |
credits_back_after_days | integer | URLs still not indexed at the final check get their credits back automatically. |
credits_expire | boolean | |
max_urls_per_submission | integer | |
buy_url | string |
Estimate cost
POST /api/v1/estimate
How many credits a submission would cost, before spending anything. Send the URLs to also learn how many are valid, duplicated or not indexable. With a credential, says whether the balance covers it.
No credential needed · MCP tool estimate_cost.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
kind | body | "standard" | "instant" | "check" | no | standard or instant indexing, or check (index checker). Default "standard". |
urls | body | array of string | no | The URLs you plan to send. |
count | body | integer | no | Or just a number of URLs. 1 to 10000. |
Example
curl -X POST "https://indexerpal.com/api/v1/estimate" \
-H "Content-Type: application/json" \
-d '{"kind":"instant","urls":["https://example.com/new-post","https://example.com/launch"]}'
Response (200)
| Field | Type | Description |
|---|---|---|
kind | "standard" | "instant" | "check" | |
urls | integer | Valid, unique URLs counted. |
invalid | integer | |
duplicates | integer | |
invalid_examples | array of string | |
credits | integer | |
balance | integer | null | |
enough | boolean | null |
4. Projects and checks
An indexing project sends its URLs through IndexerPal's indexing system and checks each one in Google; a check (kind check) only looks URLs up in Google. Both are projects: list and read them the same way.
Index URLs
POST /api/v1/projects
Creates an indexing project: IndexerPal's own indexing system gets the pages or backlinks indexed in Google (and Bing and Yandex unless turned off), then verifies each URL in Google (instant: within the hour; all: day 4 and day 14). Spends credits at once (1 per URL standard, 3 instant). Returns the project; follow it with get_project.
Scope index · needs a paid account · accepts Idempotency-Key · MCP tool submit_urls.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
urls | body | array of string | yes | Absolute http(s) URLs, up to 10,000 after duplicates and invalid entries are removed. |
mode | body | "standard" | "instant" | no | standard: 1 credit per URL, usually hours to a few days. instant: 3 credits per URL, Google first in line, in as little as a few minutes. Default "standard". |
name | body | string | no | Project name. Defaults to the first URL's domain. |
bing | body | boolean | no | Also send to Bing. Same price. Default true. |
yandex | body | boolean | no | Also send to Yandex. Same price. Default true. |
drip_days | body | 0 | 3 | 7 | 14 | 30 | no | Spread sending over this many days (0 = as fast as possible). Default 0. |
Example
curl -X POST "https://indexerpal.com/api/v1/projects" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"urls":["https://example.com/new-post","https://guest-blog.example.org/my-article"],"mode":"standard","name":"October posts"}'
Response (201)
| Field | Type | Description |
|---|---|---|
project | object | |
urls_accepted | integer | |
invalid | integer | |
duplicates | integer | |
invalid_examples | array of string | Up to 10 entries that aren't indexable URLs. |
credits_spent | integer | |
balance | integer |
Index a sitemap
POST /api/v1/projects/from-sitemap
Reads an XML sitemap (or sitemap index, one level deep; .xml.gz works) and creates an indexing project with its page URLs in one step. Set skip_already_submitted to send only URLs this account never submitted before, which suits recurring runs.
Scope index · needs a paid account · accepts Idempotency-Key · MCP tool submit_sitemap.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sitemap_url | body | string | yes | Absolute URL of the sitemap. |
skip_already_submitted | body | boolean | no | Leave out URLs already sent in an earlier project of this account. Default false. |
mode | body | "standard" | "instant" | no | standard: 1 credit per URL, usually hours to a few days. instant: 3 credits per URL, Google first in line, in as little as a few minutes. Default "standard". |
name | body | string | no | Project name. Defaults to the first URL's domain. |
bing | body | boolean | no | Also send to Bing. Same price. Default true. |
yandex | body | boolean | no | Also send to Yandex. Same price. Default true. |
drip_days | body | 0 | 3 | 7 | 14 | 30 | no | Spread sending over this many days (0 = as fast as possible). Default 0. |
Example
curl -X POST "https://indexerpal.com/api/v1/projects/from-sitemap" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"sitemap_url":"https://example.com/sitemap.xml","skip_already_submitted":true,"mode":"standard"}'
Response (201)
| Field | Type | Description |
|---|---|---|
project | object | |
urls_accepted | integer | |
invalid | integer | |
duplicates | integer | |
invalid_examples | array of string | Up to 10 entries that aren't indexable URLs. |
credits_spent | integer | |
balance | integer | |
skipped_already_submitted | integer | |
sitemap_truncated | boolean |
Add URLs to a project
POST /api/v1/projects/{project_id}/urls
Adds URLs to an existing indexing project. They are sent with the project's settings (mode, search engines, drip feed from now) and spend credits at once. URLs already in the project are skipped and cost nothing. A finished project becomes active again. Up to 10,000 URLs per call, 50,000 per project.
Scope index · needs a paid account · accepts Idempotency-Key · MCP tool add_urls.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project_id | path | string | yes | A project id, as returned by submit_urls, check_urls or list_projects. |
urls | body | array of string | yes | Absolute http(s) URLs, up to 10,000 after duplicates and invalid entries are removed. |
Example
curl -X POST "https://indexerpal.com/api/v1/projects/PROJECT_ID/urls" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"urls":["https://example.com/another-post"]}'
Response (201)
| Field | Type | Description |
|---|---|---|
project | object | |
urls_added | integer | |
already_in_project | integer | URLs skipped because the project already has them. Nothing is spent on them. |
invalid | integer | |
duplicates | integer | |
invalid_examples | array of string | Up to 10 entries that aren't indexable URLs. |
credits_spent | integer | |
balance | integer |
Check if URLs are indexed
POST /api/v1/checks
The index checker: looks each URL up in Google without sending anything. 10 URLs per credit (rounded up). Results usually arrive within the hour; read them with get_project and list_links.
Scope index · needs a paid account · accepts Idempotency-Key · MCP tool check_urls.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
urls | body | array of string | yes | Absolute http(s) URLs, up to 10,000 after duplicates and invalid entries are removed. |
name | body | string | no | Name for this check. |
Example
curl -X POST "https://indexerpal.com/api/v1/checks" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"urls":["https://example.com/a","https://example.com/b"]}'
Response (201)
| Field | Type | Description |
|---|---|---|
project | object | |
urls_accepted | integer | |
invalid | integer | |
duplicates | integer | |
invalid_examples | array of string | Up to 10 entries that aren't indexable URLs. |
credits_spent | integer | |
balance | integer |
List projects
GET /api/v1/projects
Indexing projects and index checks on this account, newest first, with their counts and index rate.
Scope read · MCP tool list_projects.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
kind | query | "all" | "index" | "check" | no | Default "all". |
status | query | "any" | "active" | "completed" | no | Default "any". |
limit | query | integer | no | Default 50. 1 to 200. |
offset | query | integer | no | Default 0. 0 to 100000. |
Example
curl "https://indexerpal.com/api/v1/projects?kind=index&limit=20" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
projects | array of object | |
has_more | boolean |
Get project
GET /api/v1/projects/{project_id}
One project or check: live counts per status, index rate, credits spent and returned.
Scope read · MCP tool get_project.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project_id | path | string | yes | A project id, as returned by submit_urls, check_urls or list_projects. |
Example
curl "https://indexerpal.com/api/v1/projects/PROJECT_ID" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
project | object |
List a project's URLs
GET /api/v1/projects/{project_id}/links
The URLs of a project with their status (scheduled, queued, pushed, sent, indexed, not_indexed, failed), dates and next check. Filter by group and search by text; paginated.
Scope read · MCP tool list_links.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project_id | path | string | yes | A project id, as returned by submit_urls, check_urls or list_projects. |
status | query | "all" | "indexed" | "checking" | "waiting" | "not_indexed" | "failed" | no | all, indexed, checking (sent, not checked yet), waiting (not sent yet), not_indexed, failed. Default "all". |
q | query | string | no | Only URLs containing this text. |
page | query | integer | no | Default 1. 1 to 9007199254740991. |
per_page | query | integer | no | Default 100. 1 to 500. |
Example
curl "https://indexerpal.com/api/v1/projects/PROJECT_ID/links?status=not_indexed&per_page=100" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
links | array of object | |
page | integer | |
pages | integer | |
total | integer | |
per_page | integer |
Cancel unsent URLs
POST /api/v1/projects/{project_id}/cancel
Takes the URLs of a project that haven't been sent yet (drip feed or queue) out, and returns their credits. URLs already sent are not affected.
Scope index · MCP tool cancel_pending_links.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project_id | path | string | yes | A project id, as returned by submit_urls, check_urls or list_projects. |
Example
curl -X POST "https://indexerpal.com/api/v1/projects/PROJECT_ID/cancel" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
removed | integer | |
credits_returned | integer | |
balance | integer | |
project | object |
Rename project
PATCH /api/v1/projects/{project_id}
Changes a project's or check's name.
Scope index · MCP tool rename_project.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project_id | path | string | yes | A project id, as returned by submit_urls, check_urls or list_projects. |
name | body | string | yes |
Example
curl -X PATCH "https://indexerpal.com/api/v1/projects/PROJECT_ID" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Launch week"}'
Response (200)
| Field | Type | Description |
|---|---|---|
project | object |
5. Sitemaps
Read a sitemap without submitting it. To index one, use submit_sitemap above.
Read a sitemap
POST /api/v1/sitemaps/read
Lists the page URLs in an XML sitemap (or sitemap index) without submitting anything. To index a whole sitemap in one step, use submit_sitemap.
Scope index · MCP tool read_sitemap.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
url | body | string | yes | Absolute URL of the sitemap. |
limit | body | integer | no | Most URLs to return. Default 1000. 1 to 10000. |
Example
curl -X POST "https://indexerpal.com/api/v1/sitemaps/read" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/sitemap.xml","limit":100}'
Response (200)
| Field | Type | Description |
|---|---|---|
urls | array of string | |
count | integer | |
returned | integer | |
sitemaps | integer | |
truncated | boolean |
6. Buying credits
A checkout link is paid by a person on Stripe; the order turns paid the moment they pay.
Buy credits
POST /api/v1/checkout
Creates a secure Stripe checkout link for a credit pack. Give checkout_url to the account owner to pay by card; credits arrive the moment they pay. Poll get_order to know when. Prices are final: nothing is added at checkout.
Scope purchase · accepts Idempotency-Key · MCP tool buy_credits.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
pack | body | "basic" | "pro" | "premium" | "agency" | yes | Credit pack: basic ($9.99, 150 credits), pro ($29.99, 500 credits), premium ($59.99, 1,100 credits), agency ($149.99, 3,000 credits). |
locale | body | "en" | "fr" | "it" | "de" | "es" | no | Language of the checkout page. Defaults to the account's language. |
Example
curl -X POST "https://indexerpal.com/api/v1/checkout" \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"pack":"premium"}'
Response (201)
| Field | Type | Description |
|---|---|---|
order | object | |
checkout_url | string | Stripe-hosted payment page. Only a person can complete it. |
expires_at | string | ISO 8601, UTC |
order_url | string | API URL to poll the order's status. |
Get order
GET /api/v1/orders/{order_id}
A credit purchase: pending until the person pays, then paid (credits added). Use it to wait for a checkout link to be paid.
Scope read · MCP tool get_order.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
order_id | path | string | yes |
Example
curl "https://indexerpal.com/api/v1/orders/ORDER_ID" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
order | object |
List orders
GET /api/v1/orders
Credit purchases on this account, newest first (paid, refunded, and checkouts still open).
Scope read · MCP tool list_orders.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | no | Default 20. 1 to 100. |
Example
curl "https://indexerpal.com/api/v1/orders?limit=10" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
orders | array of object |
Credit history
GET /api/v1/credits/history
Every change to the balance, newest first: purchases, credits spent on projects, credits back for URLs not indexed, refunds.
Scope read · MCP tool get_credit_history.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | no | Default 50. 1 to 200. |
Example
curl "https://indexerpal.com/api/v1/credits/history?limit=20" \
-H "Authorization: Bearer ipk_YOUR_KEY"
Response (200)
| Field | Type | Description |
|---|---|---|
entries | array of object |
7. Buying credits with x402
Where this deployment accepts x402, an agent can pay for a pack in USDC with no person involved. The endpoint answers 404 not_enabled where it doesn't.
POST /api/v1/credits/x402 · Scope purchase.
- Call it with
{"pack": "pro"}. The answer is402even with no credential, so the price can be read first: aPAYMENT-REQUIREDheader (x402 v2, base64 JSON) and aWWW-Authenticate: Paymentchallenge (MPP, methodevm). Both name the network, the USDC contract, the amount and the address to pay.GETon the same URL returns the same 402. A call with no pack prices the basic pack. - Sign the payment with your x402 client and send the same request again with the
PAYMENT-SIGNATUREheader andAuthorization: Bearer(an API key or an access token). A signature sent without the credential is not submitted. The official x402 client refuses any single payment over $1 by default: raisespendControls.maxAmountPerPaymentto at least the pack's price. - The payment is verified and settled; the answer is
200with the order, the new balance, the transaction and aPAYMENT-RESPONSEheader. - Each signed payment counts once: sending the same
PAYMENT-SIGNATUREagain returns the first purchase (Idempotent-Replayed: true). If the answer is409 payment_pending, the transfer is on its way: retry the same request with the same signature afterRetry-After, and don't sign a new payment.
curl -i -X POST https://indexerpal.com/api/v1/credits/x402 \
-H "Authorization: Bearer ipk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"pack": "pro"}'8. URL statuses
| Status | Meaning |
|---|---|
scheduled | Waiting for its drip-feed day. |
queued | In the queue, not sent yet. |
pushed | Being sent. |
sent | Sent; waiting for the next Google check. |
indexed | Found in Google. |
not_indexed | Not found at the final check: its credits went back to the balance. |
failed | Rejected or cancelled before sending: its credits went back. error says why (rejected, cancelled, no_answer). |
9. Errors
Errors are {"error": {"code", "message", ...}} with the HTTP status below. Branch on code; show message to people.
| Code | HTTP | Meaning and what to do |
|---|---|---|
invalid_request | 400 | A parameter is missing or wrong. issues lists each one. |
invalid_json | 400 | The body isn't a JSON object. |
no_urls | 400 | None of the URLs is a public http(s) address a search engine can index. |
too_many_urls | 400 | More URLs than one project can hold. Split them. |
unauthorized | 401 | No credential, or an invalid, revoked or expired one. WWW-Authenticate says where to sign in. |
payment_required | 402 | The account never bought credits, so it can't index yet. Create a checkout link. |
insufficient_credits | 402 | Not enough credits for this. Buy a pack, or send fewer URLs. |
insufficient_scope | 403 | The credential lacks the scope named in required_scope. |
not_found | 404 | No such endpoint, or no such object on this account. |
not_enabled | 404 | This payment method isn't enabled here. |
method_not_allowed | 405 | Wrong HTTP method for this path. |
idempotency_in_flight | 409 | A request with this Idempotency-Key (or this x402 payment) is still running. |
payment_pending | 409 | x402: the payment was sent and awaits confirmation. Send the same request with the same PAYMENT-SIGNATURE again after Retry-After; never sign a new one. |
idempotency_mismatch | 422 | This Idempotency-Key was used with a different request. |
rate_limited | 429 | Too many requests. Wait Retry-After seconds. |
daily_limit_reached | 429 | A daily quota is used up. It resets at midnight UTC. |
unavailable | 503 | Temporarily unavailable (payments, for example). Retry later. |
internal_error | 500 | Our side failed. Retry with the same Idempotency-Key. |