Errors, Pagination, and Rate Limits
The exact error response shape, error codes, paginated list format, and the real rate limits the iSearchFrom API enforces.
Every API client should handle four things: errors (with stable machine-readable codes), paginated lists, rate limits, and plan/usage limits. This page documents each precisely, with the real shapes and numbers the API uses.
Error responses
Section titled “Error responses”Every error returns JSON with a consistent shape and the failing request’s HTTP status code:
{ "statusCode": 402, "code": 39012, "message": "Insufficient token balance for this action.", "timestamp": "2026-07-07T14:05:00.000Z", "path": "/v1/tools/serp/proxy-search"}| Field | Type | Notes |
|---|---|---|
statusCode | number | The HTTP status (also on the response itself). |
code | number | Stable, machine-readable application code. Branch on this — the message can change. |
message | string | Human-readable explanation. For display and logs; never parse it. |
timestamp | string | ISO-8601 time the error was produced. |
path | string | The request path, for correlating with your logs. |
Validation errors (a malformed body or query parameter) return HTTP 400 with a message describing
the invalid field.
Error categories
Section titled “Error categories”Codes are grouped by domain. The code ranges you’ll encounter as an API client:
| Range | Domain | Typical statuses |
|---|---|---|
33xxx | API keys / authentication | 401, 403, 404 |
39xxx | Entitlements & tokens | 402, 403, 404 |
40xxx | Billing & subscriptions | 400, 403, 404, 409 |
41xxx | Search & tracking tools | 400, 404, 409, 429 |
Common error codes
Section titled “Common error codes”The codes you’re most likely to handle in an integration:
Authentication & keys
Section titled “Authentication & keys”| Code | Status | Meaning | What to do |
|---|---|---|---|
33002 | 401 | API key invalid | Check the X-API-Key header and the key value |
33003 | 403 | API key disabled | Re-enable or create a new key |
33004 | 403 | API key expired | Create a new key |
33005 | 403 | Key requests a permission the creator doesn’t hold | Reduce the requested permissions |
Entitlements & tokens
Section titled “Entitlements & tokens”| Code | Status | Meaning | What to do |
|---|---|---|---|
39005 | 403 | Plan doesn’t include this feature | Upgrade or change the workflow |
39006 | 403 | Feature usage limit reached (e.g. daily quota) | Wait for reset, upgrade, or reduce usage |
39007 | 400 | No organization context on the request | Ensure the key/session is bound to an organization |
39012 | 402 | Insufficient token balance | Top up tokens, then retry |
Search & tracking tools
Section titled “Search & tracking tools”| Code | Status | Meaning | What to do |
|---|---|---|---|
41001 | 404 | Search not found | Check the id and organization |
41002 | 404 | Campaign not found | Check the id and organization |
41003 | 409 | Campaign name already exists | Choose a unique name |
41008 | 400 | Cannot run an archived campaign | Unarchive first |
41011 | 409 | A run is already active for this campaign | Wait for it to finish |
41013 | 429 | Demo rate limit exceeded | Sign in / use an authenticated request |
Pagination
Section titled “Pagination”List endpoints return a consistent envelope:
{ "data": [{ "id": "...", "...": "..." }], "pagination": { "total": 128, "hasMore": true, "nextCursor": "eyJzIjoiY3JlYXRlZEF0Iiwi..." }}| Field | Notes |
|---|---|
data | The page of results. |
pagination.total | Total matching records (omitted on a few very large tables for speed). |
pagination.hasMore | true when more pages exist. |
pagination.nextCursor | Opaque cursor for the next page. Absent on the last page. |
Query parameters
Section titled “Query parameters”| Parameter | Default | Notes |
|---|---|---|
limit | endpoint | Page size, 1–100. Values outside the range are clamped. |
cursor | — | Pass the previous response’s nextCursor to get the next page. |
sort | endpoint | Field to sort by (allowed fields vary per endpoint). |
order | desc | asc or desc. |
Paginate by following nextCursor until hasMore is false:
curl "$BASE_URL/tools/serp/proxy-search?limit=50" -H "X-API-Key: $ISEARCHFROM_API_KEY"# then, using nextCursor from the response:curl "$BASE_URL/tools/serp/proxy-search?limit=50&cursor=eyJz...=" -H "X-API-Key: $ISEARCHFROM_API_KEY"Rate limits
Section titled “Rate limits”Limits are enforced per identity (your user or API key). When you exceed one, the API returns HTTP
429 with a Retry-After header (seconds) telling you when to try again.
| Limit group | Limit | Applies to |
|---|---|---|
| Default | 600 / minute | Almost every authenticated endpoint, including the tools |
| Authentication | 5 / minute | Login, sign-up, password reset, OTP |
| Public (unauthenticated) | 30 / minute | Anonymous reads of public resources |
| Email triggers | 10 / hour | Invites and other outbound-email actions |
The 600 requests/minute default (≈10/sec) is generous for normal automation. If an agent or job
sustains bursts near the limit, add small delays or backoff. On a 429, honor Retry-After rather
than retrying immediately.
Plan & usage limits
Section titled “Plan & usage limits”Separate from rate limits, your plan can cap:
- daily direct searches and daily proxy searches
- API and MCP access
- project count and member count
- token allocation and which product features are enabled
A request that would exceed a plan limit fails with an entitlement error (39005/39006) or, when
you’re out of tokens, 39012. There are also per-request product guardrails — for example a maximum
number of proxy pages per search, or checks per campaign run — that return a 400 when exceeded.
Retry guidance
Section titled “Retry guidance”Retry only transient failures. Never blindly retry a client error.
| Retry | Don’t retry |
|---|---|
| Transient network failures | Invalid parameters (e.g. bad country) — 400 |
| Provider timeouts | Missing permission — 403 |
429 (after Retry-After) | Plan doesn’t include feature — 39005 |
Polling a pending/running | Insufficient tokens — 39012 |
| status | Campaign exceeds a size limit — 400 |