Documentation /docs/error-handling

Error Handling

The Docspeed customer API uses standard HTTP status codes. Most product-level failures use a structured detail object. Some framework/auth failures return a plain string in detail; handle both shapes.

Common statuses

  • 400 invalid request shape or unsupported input combination
  • 401 missing or invalid bearer token
  • 402 insufficient credits
  • 422 policy or validation failure
  • 429 rate limit exceeded
  • 502 provider execution failure
  • 503 temporary unavailability

cURL

curl -sS -X POST "https://api.docspeed.ai/v1/extract" \
  -H "Authorization: Bearer ${DOCSPEED_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"input": {"text": "not a PDF or image"}, "execution_mode": "sync"}'

Python

import requests

response = requests.post(
    "https://api.docspeed.ai/v1/extract",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"input": {"text": "not a PDF or image"}, "execution_mode": "sync"},
    timeout=120,
)

if not response.ok:
    print(response.status_code, response.json())

TypeScript

const response = await fetch("https://api.docspeed.ai/v1/extract", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    input: { text: "not a PDF or image" },
    execution_mode: "sync",
  }),
});

if (!response.ok) {
  console.error(response.status, await response.json());
}

Example error body

Structured product error:

{
  "detail": {
    "code": "invalid_input",
    "message": "Schema-based extraction currently requires an image or PDF input.",
    "details": null
  }
}

Framework/auth-style error:

{
  "detail": "Missing bearer token"
}

Normalized client handling

type DocspeedErrorBody =
  | { detail: string }
  | { detail: { code?: string; message?: string; details?: unknown } };

function readDocspeedError(status: number, body: DocspeedErrorBody) {
  if (typeof body.detail === "string") {
    return { status, code: "http_error", message: body.detail, details: null };
  }
  return {
    status,
    code: body.detail.code ?? "http_error",
    message: body.detail.message ?? "Request failed",
    details: body.detail.details ?? null,
  };
}

Retry guidance

  • Retry 429 only after the Retry-After window when present.
  • Retry 502 or 503 with bounded backoff when the request is idempotent or can be safely re-submitted.
  • Do not retry 400 or 422 without changing the request body.
  • Treat 402 as a billing/credit issue, not a transient execution failure.
  • For async jobs, inspect GET /v1/jobs/{job_id} first and fetch GET /v1/jobs/{job_id}/result only after completed or for failure diagnostics.