Quick start

Three steps. Under a minute.

1

Generate your API key

Open /dashboard/api-tokens and click Generate API key. Copy the mi_… string — it's only shown once.

2

Make your first request

# Submit a URL for indexing
curl -X POST "https://monkeyindexer.com/api/v1/submit" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
3

Get instant confirmation

{
  "success": true,
  "message": "1 URL submitted successfully",
  "data": {
    "submitted": 1,
    "tracking_ids": ["01KTAA01H8QZ7Y3M5N6P0R8V2X"],
    "credits_remaining": 149
  }
}

Authentication

Every authenticated request needs your API key. Pick whichever transport is easiest for your client — all three are equivalent.

Recommended: Authorization header

Authorization: Bearer mi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Alternative: X-API-Key header

X-API-Key: mi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Alternative: query parameter

GET https://monkeyindexer.com/api/v1/me?api_key=mi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

⚠️ Note: the query-string form is logged by web servers and may leak via the Referer header. Prefer one of the header methods in production.

Token lifetime

API keys expire 30 days after generation. Regenerating creates a new key and immediately revokes the old one — there is no grace period.

Response envelope

Every response — success or error — uses the same JSON shape:

{
  "success": true | false,
  "message": "human-readable summary",
  "data": { ... } | null
}

HTTP status code reflects the outcome — 200 for success, 4xx for client errors, 5xx for server errors. Parse success + HTTP status together for the safest behaviour.

Errors

Standard HTTP status codes. Body is always the envelope above.

200
OK — request succeeded
401
Unauthenticated — missing, invalid, or expired API key
402
Insufficient credits — top up at /dashboard/billing
405
Method not allowed for this endpoint
422
Invalid input — see message for details
429
Rate limited — see Retry-After header
500
Server error — retry with exponential backoff
503
Indexing temporarily paused — see data.error_code = "indexing_paused". Treat as transient; retry later.

Paused / maintenance response

When operators globally pause indexing for maintenance, every POST /api/v1/submit returns HTTP 503 with this body. The machine-readable identifier data.error_code = "indexing_paused" is stable — branch on that, not on the human message.

HTTP/1.1 503 Service Unavailable
Content-Type: application/json

{
  "success": false,
  "message": "URL indexing is temporarily paused for maintenance. Please try again in a little while.",
  "data": {
    "error_code": "indexing_paused"
  }
}

Rate limits

Three independent sliding windows per API key. Exceed any one and you get a 429.

Per minute
60
Per hour
1,000
Per day
10,000

Every response carries the remaining counts:

X-RateLimit-Limit-Minute: 60
X-RateLimit-Remaining-Minute: 58
X-RateLimit-Limit-Hour: 1000
X-RateLimit-Remaining-Hour: 994
X-RateLimit-Limit-Day: 10000
X-RateLimit-Remaining-Day: 9847
GET/api/v1

Health check

Verify the API is reachable. No authentication required.

curl "https://monkeyindexer.com/api/v1"

# Response
{
  "success": true,
  "message": "MonkeyIndexer API v1.0 is running",
  "data": { "version": "1.0", "status": "operational" }
}
GET/api/v1/me

Account & wallet

Returns your user profile, wallet balance, the active token's metadata, and your remaining rate-limit budget so clients can throttle themselves intelligently.

curl "https://monkeyindexer.com/api/v1/me" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Response
{
  "success": true,
  "message": "Account retrieved successfully",
  "data": {
    "user": { "id": "01KT...4Y2", "name": "Alice", "email": "alice@example.com" },
    "credits": {
      "balance": 249, "reserved": 0, "available": 249,
      "lifetime_used": 51, "lifetime_purchased": 200
    },
    "token": {
      "created_at": "2026-06-05T10:00:00+05:30",
      "expires_at": "2026-07-05T10:00:00+05:30",
      "last_used_at": "2026-06-05T18:23:00+05:30"
    },
    "rate_limit": { "remaining_minute": 58, "remaining_day": 9847 }
  }
}
POST/api/v1/submit

Submit URL(s) for indexing

Submit a single URL or a batch (up to 50 URLs per call). Each URL costs 1 credit. The response carries ULID tracking IDs you can poll on /submissions.

Body — single URL

{ "url": "https://example.com/page" }

Body — batch (up to 50)

{
  "urls": [
    "https://example.com/page-1",
    "https://example.com/page-2",
    "https://example.com/page-3"
  ]
}

curl

curl -X POST "https://monkeyindexer.com/api/v1/submit" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/page"}'

JavaScript (fetch)

const r = await fetch('https://monkeyindexer.com/api/v1/submit', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ url: 'https://example.com/page' }),
});
const data = await r.json();

PHP (Guzzle)

$client = new \GuzzleHttp\Client();
$res = $client->post('https://monkeyindexer.com/api/v1/submit', [
    'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
    'json'    => ['url' => 'https://example.com/page'],
]);
$data = json_decode($res->getBody(), true);

Python (requests)

import requests
r = requests.post(
    'https://monkeyindexer.com/api/v1/submit',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={'url': 'https://example.com/page'},
)
data = r.json()

Response — success

{
  "success": true,
  "message": "1 URL submitted successfully",
  "data": {
    "submitted": 1,
    "rejected": 0,
    "invalid_urls": [],
    "tracking_ids": ["01KTAA01H8QZ7Y3M5N6P0R8V2X"],
    "credits_remaining": 248
  }
}

Response — insufficient credits

HTTP 402
{
  "success": false,
  "message": "Insufficient credits to submit this URL.",
  "data": { "submitted": 0, "credits_remaining": 0 }
}
GET/api/v1/submissions

List submissions

Lists your recent submissions, newest first. Filter by tracking IDs, URLs, or status. Paginated.

Query parameters

ids
string
Comma-separated ULIDs (max 100)
urls
string
Comma-separated URLs (max 100)
status
string
queued | processing | submitted | indexed | not_indexed | failed | refunded
limit
integer
Items per page (default 20, max 100)
page
integer
Page number (default 1)

Example

curl "https://monkeyindexer.com/api/v1/submissions?status=indexed&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Response
{
  "success": true,
  "message": "Submissions retrieved successfully",
  "data": {
    "count": 10,
    "total": 1043,
    "page": 1,
    "per_page": 10,
    "items": [
      {
        "tracking_id": "01KTAA01H8QZ7Y3M5N6P0R8V2X",
        "url": "https://example.com/page",
        "status": "indexed",
        "provider_status": "Delivered",
        "submitted_at": "2026-06-05T10:00:00+05:30",
        "crawled_at": "2026-06-05T11:30:00+05:30",
        "created_at": "2026-06-05T09:59:55+05:30"
      }
    ]
  }
}

Postman collection

One-click import. Pre-configured environment variables for {{base_url}} and {{api_key}}. Every endpoint with example requests and responses.

How to import

1 Download the collection JSON below.
2 In Postman, click Import → drag the file in.
3 In the collection's Variables tab, set api_key to your mi_… key. base_url defaults to https://monkeyindexer.com.
4 Send any request. Auth is wired up via collection-level Bearer token.

Changelog

What changed and when. Breaking changes will always ship a new major version (e.g. /api/v2) — the v1 surface is stable.

v1.0
today
Initial release.
  • GET /api/v1 — health check, no auth
  • GET /api/v1/me — user + wallet + token + rate-limit snapshot
  • POST /api/v1/submit — single URL or batch (up to 50)
  • GET /api/v1/submissions — paginated list with ids/urls/status filters
  • Three auth methods: Authorization: Bearer, X-API-Key, ?api_key=
  • 30-day token expiry; single active key per user
  • Per-token rate limits: 60/min · 1,000/h · 10,000/day