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":"standard"}
- A single URL may be sent with "url"; multiple URLs use the "urls" array.
- Send 1-5000 unique HTTP(S) URLs per submission.
- Use service "standard". Do not select "fast" unless the account explicitly confirms that service is enabled.
- 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
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 statisticsRequiredKeep 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())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.