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
400invalid request shape or unsupported input combination401missing or invalid bearer token402insufficient credits422policy or validation failure429rate limit exceeded502provider execution failure503temporary 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
429only after theRetry-Afterwindow when present. - Retry
502or503with bounded backoff when the request is idempotent or can be safely re-submitted. - Do not retry
400or422without changing the request body. - Treat
402as a billing/credit issue, not a transient execution failure. - For async jobs, inspect
GET /v1/jobs/{job_id}first and fetchGET /v1/jobs/{job_id}/resultonly aftercompletedor for failure diagnostics.