Idempotency-Key
Reuse the same key when retrying an uncertain POST. The original result is returned without a second charge; different content with the same key returns HTTP 409.
Use one secure REST API to submit authorized URLs, read your balance, list jobs, inspect URL states, and retrieve account statistics.
The Index Grab API is a JSON-based REST interface for the same balance, pricing, queue, and processing records used by the customer dashboard. API submissions enter the regular background workflow and return a reference you can query without keeping a connection open.
Authentication supports a Bearer token or X-API-Key header. API keys are created in the authenticated dashboard, shown once, stored only as a secure hash, and remain valid until you revoke or regenerate them.
https://indexgrab.com/api/v1Copy this concise technical brief into ChatGPT, Claude, Gemini, or another coding assistant. It describes the real API contract without requiring the model to infer rules from the page.
# Index Grab REST API v1 - AI integration brief
Use this specification to generate a server-side Index Grab integration. Do not expose the API key in browser code, mobile bundles, repositories, client logs, or responses sent to end users.
Base URL: https://indexgrab.com/api/v1
Protocol: HTTPS REST API with JSON request and response bodies
Authentication: Authorization: Bearer YOUR_API_KEY
Alternative authentication: X-API-Key: YOUR_API_KEY
Currency: TRY
Create a submission:
- Method and path: POST /submissions
- Required headers: Authorization, Content-Type: application/json, and Idempotency-Key
- Idempotency-Key must contain 8-100 safe characters.
- Request body: {"project":"My Website","urls":["https://example.com/page"],"service":"fast"}
- A single URL may be sent with "url"; multiple URLs use the "urls" array.
- Send 1-5000 unique HTTP(S) URLs per submission.
- Service "fast" selects Instant Index (may process in 5-10 minutes). Service "standard" selects Standard Index (may process in 3 hours to 7 days). If service is omitted, the current API default is "fast".
- The account's current per-URL price is applied and the required balance is charged when the submission is accepted.
Submission workflow:
- HTTP 202 means accepted and queued, not indexed by a search engine.
- Save data.reference from the response.
- Query GET /submissions/{reference} to read the job and per-URL states.
- Possible job states: queued, processing, completed, partial, failed.
- Poll with a reasonable delay, such as 10-30 seconds, and stop when a terminal state is reached.
- Index Grab processing states do not guarantee search-engine indexing.
Safe retry rule:
- If a POST result is uncertain because of a timeout or connection loss, retry the exact same body with the exact same Idempotency-Key.
- The same key and same body return the original submission without a second charge.
- The same key with different content returns HTTP 409.
Read endpoints:
- GET /me: account, wallet, and API-key metadata
- GET /balance: current balance and TRY currency
- GET /submissions: paginated history; supports status, reference, url, q, from, to, page, and limit
- GET /submissions/{reference}: submission details and paginated URL states
- GET /stats: balance and submission statistics
URL result check:
- Availability: Beta. The endpoint may temporarily return HTTP 503 with a retryable error. A rejected check is not charged; a charge made before an execution failure is restored.
- Method and path: POST /index-check
- Required headers: Authorization, Content-Type: application/json, and Idempotency-Key
- Request body: {"urls":["https://example.com/page"]}
- Checks 1-50 unique URLs against current public search results and charges the configured per-URL check price only after validation.
- A found result means the URL appeared in the checked result data at that moment; it is not a permanent indexing guarantee.
Response envelope:
- Success: {"success":true,"status":"success","message":"...","data":{},"request_id":"..."}
- Error: {"success":false,"status":"error","message":"...","data":null,"error":{"code":"...","message":"..."},"request_id":"..."}
- Read HTTP status codes as well as the JSON envelope.
Current limits per API key:
- General requests: 120/minute, 3000/hour, 30000/day
- Submission requests: 10/minute
- List page limit: 100; submission-detail URL page limit: 500
- On HTTP 429, respect Retry-After and rate-limit response headers.
Important errors:
- 400 invalid JSON, request, or Idempotency-Key
- 401 missing, invalid, or revoked API key
- 402 insufficient balance
- 409 idempotency or duplicate conflict
- 413 payload too large
- 415 Content-Type is not application/json
- 422 validation error
- 429 rate limit exceeded
- 503 API or submission service temporarily unavailable
Machine-readable contract: https://indexgrab.com/api/v1/openapi.jsonAll authenticated endpoints return a consistent JSON envelope and rate-limit headers.
/Health and availabilityPublic/meAccount, wallet and key metadataRequired/balanceCurrent account balanceRequired/submissionsCreate a queued URL submissionRequired/submissionsFilter and paginate job historyRequired/submissions/{reference}Job details and URL statesRequired/statsBalance and submission statisticsRequired/index-checkBeta URL result check, 0.50 TRY per URLAvailableKeep the API key in a server-side environment variable. Never include it in public browser JavaScript, mobile application bundles, repositories, analytics, or client-visible logs.
curl -X POST "https://indexgrab.com/api/v1/submissions" \
-H "Authorization: Bearer $INDEXGRAB_API_KEY" \
-H "Idempotency-Key: job-20260801-001" \
-H "Content-Type: application/json" \
-d '{"project":"My Website","url":"https://example.com/page"}'<?php
$payload = json_encode([
'project' => 'My Website',
'urls' => ['https://example.com/page'],
]);
$ch = curl_init('https://indexgrab.com/api/v1/submissions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INDEXGRAB_API_KEY'),
'Idempotency-Key: job-20260801-001',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $payload,
]);
$result = json_decode(curl_exec($ch), true);// Node.js 18+
const response = await fetch('https://indexgrab.com/api/v1/submissions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INDEXGRAB_API_KEY}`,
'Idempotency-Key': `job-${crypto.randomUUID()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
project: 'My Website',
urls: ['https://example.com/page']
})
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());import os, uuid, requests
response = requests.post(
'https://indexgrab.com/api/v1/submissions',
headers={
'Authorization': f'Bearer {os.environ["INDEXGRAB_API_KEY"]}',
'Idempotency-Key': f'job-{uuid.uuid4()}',
},
json={'project': 'My Website', 'urls': ['https://example.com/page']},
timeout=30,
)
response.raise_for_status()
print(response.json())POST /index-check accepts 1-50 unique HTTP(S) URLs. Each URL costs 0.50 TRY. This beta service may be temporarily limited; HTTP 503 means no check was performed and no balance was charged or the charge was restored. Results describe only the checked moment.
Current status: Available (Beta)
curl -X POST "https://indexgrab.com/api/v1/index-check" \
-H "Authorization: Bearer $INDEXGRAB_API_KEY" \
-H "Idempotency-Key: check-20260815-001" \
-H "Content-Type: application/json" \
-d '{"urls":["https://example.com/page"]}'<?php
$payload = json_encode(['urls' => ['https://example.com/page']]);
$ch = curl_init('https://indexgrab.com/api/v1/index-check');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INDEXGRAB_API_KEY'),
'Idempotency-Key: check-' . bin2hex(random_bytes(8)),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $payload,
]);
print_r(json_decode(curl_exec($ch), true));const response = await fetch('https://indexgrab.com/api/v1/index-check', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.INDEXGRAB_API_KEY}`,
'Idempotency-Key': `check-${crypto.randomUUID()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ urls: ['https://example.com/page'] })
});
console.log(await response.json());import os, uuid, requests
response = requests.post(
'https://indexgrab.com/api/v1/index-check',
headers={
'Authorization': f'Bearer {os.environ["INDEXGRAB_API_KEY"]}',
'Idempotency-Key': f'check-{uuid.uuid4()}',
},
json={'urls': ['https://example.com/page']},
timeout=90,
)
response.raise_for_status()
print(response.json())Design for queued processing instead of holding a request open until every URL finishes.
Reuse the same key when retrying an uncertain POST. The original result is returned without a second charge; different content with the same key returns HTTP 409.
Read the remaining minute, hour, and day budgets in every authenticated response. Current limits are 120/minute, 3000/hour, and 30000/day per key.
HTTP 202 means the job was accepted and queued. Save its reference and query the detail endpoint; it does not mean a search engine has indexed every URL.
Create your key, download the integration specification, and test with one authorized URL.