Developers
Sign in
Reference

CrawlMe API v1 Supported

The original API. It is fully supported and existing integrations continue working without any changes.

API v2 is now available with improved batch tracking, safer retries, and an enhanced developer experience. Existing API v1 integrations will continue working normally. Upgrading is optional. See the v2 reference or the migration guide.

Overview

Base URL:

Base URL
https://crawlme.net/api/v1

Four endpoints. Except for /submission/{id}, paths include the .php suffix.

MethodPathPurpose
GET/balance.phpYour credit balance
POST/submit.phpSubmit URLs under your own account and balance
GET/submission/{id}One submission's status (also available as /submission.php?id={id})
GET/submissions.phpPaginated list of your submissions, optionally filtered by status

Every response is JSON with one of two envelopes:

JSON
{"success": true, "data": { ... }}
{"success": false, "error": {"code": "ERROR_CODE", "message": "Human-readable explanation"}}

Timestamps are UTC in YYYY-MM-DD HH:MM:SS form. Monetary values (balance, credits_used) are JSON numbers with two decimals.

Authentication

Send your API key as a Bearer token with every request. Keys are created on the API Access page of your dashboard and start with uidx_. Regenerating a key revokes the previous one immediately.

HTTP
Authorization: Bearer YOUR_API_KEY

The same key also works with API v2. Revoking it, or an Admin disabling API access for the account, closes both versions at once.

Balance

GET/api/v1/balance.php#

cURL
curl -X GET "https://crawlme.net/api/v1/balance.php" \
  -H "Authorization: Bearer YOUR_API_KEY"
PHP
<?php
$ch = curl_init("https://crawlme.net/api/v1/balance.php");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'GET',
    CURLOPT_HTTPHEADER     => [
    'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($response['success']) {
    print_r($response['data']);
} else {
    echo $status . ' ' . $response['error']['code'] . ': ' . $response['error']['message'];
}
Python
import requests

response = requests.get(
    "https://crawlme.net/api/v1/balance.php",
    headers={
    "Authorization": "Bearer YOUR_API_KEY",
    },
    timeout=30,
)
body = response.json()

if body["success"]:
    print(body["data"])
else:
    print(response.status_code, body["error"]["code"], body["error"]["message"])
JavaScript
const response = await fetch("https://crawlme.net/api/v1/balance.php", {
  method: "GET",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
  },
});
const body = await response.json();

if (body.success) {
  console.log(body.data);
} else {
  console.error(response.status, body.error.code, body.error.message);
}
JSON
{
    "success": true,
    "data": {
        "balance": 150.0
    }
}

Submit URLs

POST/api/v1/submit.php#

Body: a JSON object with a urls array. Minimum 1 URLs, maximum 1,000 per call. Non-string entries and blank strings are ignored.

cURL
curl -X POST "https://crawlme.net/api/v1/submit.php" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com/page-1","https://example.com/page-2","not a url"]}'
PHP
<?php
$ch = curl_init("https://crawlme.net/api/v1/submit.php");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'POST',
    CURLOPT_HTTPHEADER     => [
    'Authorization: Bearer YOUR_API_KEY',
    'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode(['urls' => ['https://example.com/page-1', 'https://example.com/page-2', 'not a url']]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($response['success']) {
    print_r($response['data']);
} else {
    echo $status . ' ' . $response['error']['code'] . ': ' . $response['error']['message'];
}
Python
import requests

response = requests.post(
    "https://crawlme.net/api/v1/submit.php",
    headers={
    "Authorization": "Bearer YOUR_API_KEY",
    },
    json={"urls":["https://example.com/page-1","https://example.com/page-2","not a url"]},
    timeout=30,
)
body = response.json()

if body["success"]:
    print(body["data"])
else:
    print(response.status_code, body["error"]["code"], body["error"]["message"])
JavaScript
const response = await fetch("https://crawlme.net/api/v1/submit.php", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"urls":["https://example.com/page-1","https://example.com/page-2","not a url"]}),
});
const body = await response.json();

if (body.success) {
  console.log(body.data);
} else {
  console.error(response.status, body.error.code, body.error.message);
}

Response 201 Created:

JSON
{
    "success": true,
    "data": {
        "batch_id": 293244,
        "submitted_count": 2,
        "invalid": [
            "not a url"
        ],
        "duplicates": []
    }
}
FieldTypeMeaning
batch_idintegerThe batch that groups the accepted URLs. Use it with v2's /batches/{id} if you want a summary.
submitted_countintegerHow many URLs were accepted, queued and charged.
invalidstring[]Entries that are not well-formed http(s) URLs, echoed exactly as you sent them.
duplicatesstring[]URLs skipped because they repeat an earlier entry in the same call, or were submitted by your account in the last 1 minutes.

Partial acceptance. Valid, non-duplicate URLs are accepted even when others are invalid or duplicates. You are charged 1 credit per accepted URL, all at once. If your balance cannot cover every accepted URL, the call fails and nothing is charged or queued.

Retries. v1 has no idempotency header. If you repeat an identical request within 1 minutes, every URL is reported as a duplicate and nothing is charged. After that window the same URLs are accepted and charged again. For guaranteed retry safety use v2's Idempotency-Key.

One submission

GET/api/v1/submission/{id}#

Returns one submission you may see: your own, or (for Reseller keys) one belonging to one of your Customers. Any other id returns 404, whether or not it exists. /submission.php?id={id} is equivalent.

cURL
curl -X GET "https://crawlme.net/api/v1/submission/8812001" \
  -H "Authorization: Bearer YOUR_API_KEY"
PHP
<?php
$ch = curl_init("https://crawlme.net/api/v1/submission/8812001");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'GET',
    CURLOPT_HTTPHEADER     => [
    'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($response['success']) {
    print_r($response['data']);
} else {
    echo $status . ' ' . $response['error']['code'] . ': ' . $response['error']['message'];
}
Python
import requests

response = requests.get(
    "https://crawlme.net/api/v1/submission/8812001",
    headers={
    "Authorization": "Bearer YOUR_API_KEY",
    },
    timeout=30,
)
body = response.json()

if body["success"]:
    print(body["data"])
else:
    print(response.status_code, body["error"]["code"], body["error"]["message"])
JavaScript
const response = await fetch("https://crawlme.net/api/v1/submission/8812001", {
  method: "GET",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
  },
});
const body = await response.json();

if (body.success) {
  console.log(body.data);
} else {
  console.error(response.status, body.error.code, body.error.message);
}
JSON
{
    "success": true,
    "data": {
        "id": 8812001,
        "batch_id": 293244,
        "url": "https://example.com/page-1",
        "status": "PROCESSING",
        "credits_used": 1.0,
        "submitted_at": "2026-10-23 09:15:02",
        "updated_at": "2026-10-23 09:18:40",
        "completed_at": null
    }
}
statusMeaning
PENDINGAccepted and charged, waiting for the background worker to send it to a provider.
PROCESSINGA provider has accepted it and is working on it.
SUCCESSThe provider reported success. This does not confirm that search engines have indexed the page.
FAILEDThe provider could not process it, or it could not be sent after several attempts. The credit was refunded.
CANCELLEDReserved value for a submission cancelled before processing. Refunded like FAILED. Not produced by normal API use today.

List submissions

GET/api/v1/submissions.php#

Query parameterDefaultMeaning
page1Page number, starting at 1.
limit25Rows per page, 1 to 100.
status(none)Exact-case filter: PENDING, PROCESSING, SUCCESS, FAILED or CANCELLED. Any other value is ignored and the list is unfiltered.
cURL
curl -X GET "https://crawlme.net/api/v1/submissions.php?page=1&limit=25&status=SUCCESS" \
  -H "Authorization: Bearer YOUR_API_KEY"
PHP
<?php
$ch = curl_init("https://crawlme.net/api/v1/submissions.php?page=1&limit=25&status=SUCCESS");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'GET',
    CURLOPT_HTTPHEADER     => [
    'Authorization: Bearer YOUR_API_KEY',
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($response['success']) {
    print_r($response['data']);
} else {
    echo $status . ' ' . $response['error']['code'] . ': ' . $response['error']['message'];
}
Python
import requests

response = requests.get(
    "https://crawlme.net/api/v1/submissions.php?page=1&limit=25&status=SUCCESS",
    headers={
    "Authorization": "Bearer YOUR_API_KEY",
    },
    timeout=30,
)
body = response.json()

if body["success"]:
    print(body["data"])
else:
    print(response.status_code, body["error"]["code"], body["error"]["message"])
JavaScript
const response = await fetch("https://crawlme.net/api/v1/submissions.php?page=1&limit=25&status=SUCCESS", {
  method: "GET",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
  },
});
const body = await response.json();

if (body.success) {
  console.log(body.data);
} else {
  console.error(response.status, body.error.code, body.error.message);
}
JSON
{
    "success": true,
    "data": {
        "submissions": [
            {
                "id": 8812002,
                "batch_id": 293244,
                "url": "https://example.com/page-2",
                "status": "SUCCESS",
                "credits_used": 1.0,
                "submitted_at": "2026-10-23 09:15:02",
                "updated_at": "2026-10-23 11:02:11",
                "completed_at": "2026-10-23 11:02:11"
            }
        ],
        "pagination": {
            "page": 1,
            "per_page": 25,
            "total": 1,
            "total_pages": 1
        }
    }
}

Newest first. Reseller keys see their own submissions and their Customers' submissions; Customer keys see only their own.

Response codes

Every status the v1 endpoints return, in the order a request can meet them. Nothing is charged when a call returns an error.

HTTPcodemessageWhen
200--Success. data holds the balance, one submission, or a page of submissions.
201--POST /submit.php created a batch.
503MAINTENANCEThe API is temporarily unavailable for maintenance.The platform is in maintenance mode. Retry later.
405METHOD_NOT_ALLOWEDUse GET for this endpoint. / Use POST for this endpoint.Wrong HTTP method.
401UNAUTHENTICATEDMissing or malformed Authorization header. Expected: Authorization: Bearer <api_key>No Authorization header, or not in the form Bearer <key>.
401UNAUTHENTICATEDInvalid or revoked API key.Unknown, revoked or regenerated key, or the account is disabled.
403FORBIDDENAPI access is not enabled for this account. Contact an Admin to enable it.The key is valid but API access is switched off for the account.
429RATE_LIMITEDToo many requests. Please slow down.More than 60 requests in 60 seconds for this account (v1 and v2 calls combined). Wait and retry. v1 sends no Retry-After header.
400INVALID_JSONRequest body must be valid JSON.The body could not be parsed as a JSON object.
400VALIDATION_ERRORRequest body must include a "urls" array.urls is missing or not an array.
400VALIDATION_ERRORNo URLs provided.urls contains no non-empty string entries.
400VALIDATION_ERRORA valid submission id is required.The id in /submission/{id} is missing or not a positive number.
404NOT_FOUNDSubmission not found.The submission does not exist or is outside your scope. Both cases give the same answer on purpose.
400SUBMISSION_FAILEDMaximum N URLs per batch — you submitted M.More than 1,000 URLs. Split the request.
400SUBMISSION_FAILEDNo active indexing provider is currently configured. Please try again later.No provider is available right now. Retry later.
400SUBMISSION_FAILEDNo valid, non-duplicate URLs to submit.Every URL was invalid or a duplicate.
400SUBMISSION_FAILEDPlease submit at least N URLs (only M valid, non-duplicate URLs found).Fewer valid URLs than the minimum of 1.
400SUBMISSION_FAILEDInsufficient credits for this submission.Balance too low (accounts registered directly with the platform).
400SUBMISSION_FAILEDInsufficient balance for this submission.Balance too low (Reseller accounts and accounts managed by a Reseller).
400SUBMISSION_FAILEDSubmission failed. Please contact your site administrator.Accounts managed by a Reseller only: the Reseller's pooled balance cannot cover the request.
400SUBMISSION_FAILEDSubmission failed. Please try again.Unexpected server error during submission. Retry, and contact support if it persists.
500SERVER_ERRORAn internal error occurred.Unexpected server error elsewhere.

Rate limit

60 requests per minute per account, counted over a sliding 60-second window. The limit belongs to the account, not the key, so regenerating a key does not reset it, and requests to API v1 and API v2 count against the same allowance. Rejected requests are not counted.