Error codes[01]

Error codes

Every error returns JSON with a stable code and a human-readable message.

Error shape

[02]

All Read API errors share the same body. The HTTP status code mirrors the standard meaning; the code field is what you should branch on in code (messages can change wording without notice).

Error shape[json]
{
  "status": "error",
  "code": "RATE_LIMITED",
  "message": "Monthly quota exceeded",
  "retry_after": "2026-06-01T00:00:00.000Z"
}

Extra details sit at the top level of the body, next to code — not in a nested object:

Code · Extra fields
CONCURRENT_LIMIT

in_flight, limit, retry_after (always 1, in seconds)

RATE_LIMITED

retry_after — an ISO date for the end of the UTC month

PAYMENT_REQUIRED

plan_limit, credits_remaining

Codes

[03]

Every code links to its dedicated reference page with full handling guidance, an example response body, retry semantics, and a TypeScript snippet.

Code · HTTP · When · What to do

The url was missing or unparseable, used a scheme other than http(s), or pointed at a private or internal host.

The /v1/batch body wasn't JSON, had neither urls nor site, or listed no valid URLs.

Defined for an empty discovery result, but /v1/map always returns at least the start URL.

The Authorization header is missing, malformed, or holds a key that isn't active.

A paid plan used up its monthly credits and has no bought credits left.

The target site refused Onto's crawler (the origin returned 401 or 403).

The site's robots.txt has Disallow: / for GPTBot or for every user agent.

The action needs a higher plan, such as buying credits on the Free plan.

The target URL returned 404, or its hostname doesn't resolve.

The document is over 10 MB, the most Onto will read.

The URL returned something Onto can't read as a document, like an image, video or archive.

The URL is a scanned PDF with no text layer, so there's no text to extract.

Free plan: this month's credits are used up. They reset at the start of the next UTC month.

Too many requests running at once for your plan. Wait a second and retry.

The fetch or the parse failed: an origin error, an unreachable host, a redirect problem, or a page or PDF Onto couldn't parse.

The target site's TLS certificate or handshake failed, so Onto couldn't connect securely.

TIMEOUT[504]

The target site didn't respond within 15 seconds.

Handling

[04]

Suggested branching in a Node client:

const r = await fetch(url, opts);
const data = await r.json();

if (!r.ok) {
  switch (data.code) {
    case 'CONCURRENT_LIMIT':
      // Slot is full; retry_after is always 1 (second).
      await sleep((data.retry_after ?? 1) * 1000);
      return retry();

    case 'RATE_LIMITED':
    case 'PAYMENT_REQUIRED':
      // Out of monthly credits (Free), or out of bought credits too (paid).
      // Don't retry blindly — escalate.
      notifyOps(`Onto quota exhausted: ${data.message}`);
      throw new Error(data.message);

    case 'ROBOTS_BLOCKED':
      // The site asked us not to crawl. Honor it; skip silently.
      return null;

    case 'WAF_BLOCKED':
    case 'URL_NOT_FOUND':
      // Origin issue; skip this URL.
      return null;

    case 'TIMEOUT':
    case 'EXTRACTION_FAILED':
      // Transient; errors are never cached, so just retry once.
      return retry();

    default:
      throw new Error(`Onto: ${data.code} — ${data.message}`);
  }
}