Skip to content

Errors & Rate Limits

Factum Parse uses ordinary HTTP status codes and application/problem+json for structured API errors.

Status Meaning Typical source
200 Success Normal parse/upload/status response
202 Accepted Async parse (async_mode=true)
400 Bad request Empty upload body, malformed JSON
401 Unauthorized Missing/invalid X-API-Key (fail-closed, constant-time compare)
404 Not found Unknown upload job_id
413 Payload too large Body/file above 10 MiB (max_upload_bytes / max_body_bytes)
415 Unsupported media type/document Unsupported file (non XML/PDF)
422 Unprocessable entity Invalid FatturaPA XML, invalid text bounds/encoding, XOR violation, async/text conflict
429 Too many requests Rate-limit middleware, when enabled
500 Internal error Unexpected provider/privacy/database/runtime failure
503 Service unavailable Required Rizzo sidecar unavailable (fail-closed privacy block)

Tutti gli errori business restituiscono Content-Type: application/problem+json:

{
"type": "about:blank",
"title": "Tipo di file non supportato",
"status": 415,
"detail": "contenuto non riconosciuto: attesi PDF o FatturaPA XML",
"instance": "7c6f2d1c-..."
}
Campo Tipo Descrizione
type string URI del tipo di problema ("about:blank" per default)
title string Titolo leggibile dell’errore
status integer HTTP status code
detail string Descrizione specifica del problema
instance string | null Request-ID o UUID generato

Dettaglio 422 — violazioni ParseRequest (testo diretto)

Section titled “Dettaglio 422 — violazioni ParseRequest (testo diretto)”
Condizione detail
text < 80 caratteri Testo troppo corto: minimo 80 caratteri
text > 200.000 caratteri Testo troppo lungo: massimo 200.000 caratteri
async_mode=true + text text supporta solo elaborazione sincrona (payload in RAM)
job_id e text entrambi serve esattamente una sorgente: job_id oppure text
job_id e text entrambi assenti serve esattamente una sorgente: job_id oppure text
callback_url senza async_mode=true callback_url richiede async_mode=true
Condizione detail
PDF senza layer di testo (< 80 char) scanned_document: il PDF non contiene testo estraibile
PDF > 50 pagine Il PDF supera il limite massimo di 50 pagine
XML non conforme a FatturaPA XML non valido o non conforme al formato FatturaPA
Content-Type non supportato contenuto non riconosciuto: attesi PDF o FatturaPA XML

Rate limiting is configurable via backend settings (app/services/ratelimit.py header X-Tier, values free | basic | pro, default free). Do not treat old tier tables as a stable public API contract unless the deployment configuration and middleware are re-verified.

Current configured limits:

Tier Limite Finestra
free 60 req/min 1 min
basic 100 req/min 1 min
pro 1000 req/min 1 min

When rate limiting is enabled, 429 Too Many Requests includes rate limit headers:

Retry-After: 45
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 45

Note operative:

  • Il rate limit è fail-open: se Redis è irraggiungibile (RATE_LIMIT_REQUIRED=false), le richieste passano (non blocca il servizio). RATE_LIMIT_REQUIRED=true → Redis giù = 503.
  • Gira prima dell’auth (ASGI middleware): richieste non autenticate consumano quota.
  • Il retry loop wait_ready() (10 tentativi, 2s caduno) garantisce Redis connesso prima che il server inizi a servire.
  • Chiave di rate-limit: X-API-Key o, in assenza, IP del client (con anti-spoofing XFF).

POST /v1/uploads accepts:

X-Request-Id: 7c6f2d1c-...

The value is used as the RFC 7807 instance field. If absent, the upload router generates a UUID for the error instance.

Important: the backend does not currently implement a global X-Request-ID response header across all routes. Therefore the documentation does not pretend that such a header is universally available. A future global request-ID middleware should be treated as a backend feature and tested before this page is changed.

  • 400 / 401 / 404 / 415 / 422: fix the request; blind retries are usually wrong.
  • 429: retry with backoff according to the deployment’s rate-limit policy.
  • 500: retry only when the operation is safe to repeat; preserve request context.
  • 503: treat as a privacy boundary failure; retry after backoff rather than bypassing the sidecar.