Schemas — DocumentEnvelope v2
Il contratto di output di Factum Parse prevede due livelli ben distinti:
il wrapper HTTP (ParseResponse / DocumentResponse) e l’envelope interno
DocumentEnvelope v2 (il contenuto semanticamente validato).
Source of truth: backend/app/schemas/envelope.py.
DocumentEnvelope v2 — il contratto del contenuto
Section titled “DocumentEnvelope v2 — il contratto del contenuto”È l’unico formato wire del risultato di parsing, sia per upload che per
parse diretto. I vecchi record v1 vengono convertiti on-read (vedi
backend/app/services/envelope.py): niente dualità wire.
Top-level contract
Section titled “Top-level contract”{ "schema_version": "2.0", "document_type": "invoice", "meta": { "cost_eur": 0.0, "confidence": 1.0, "provider": "fast-path", "prompt_version": "fast-path-v1" }, "payload": { "kind": "invoice", "dati_trasmissione": {}, "cedente_prestatore": {}, "cessionario_committente": {}, "corpi": [] }}| Field | Pydantic type | Default | Contract |
|---|---|---|---|
schema_version |
Literal["2.0"] |
"2.0" |
Fixed wire version |
document_type |
Literal["invoice", "generic"] |
— | Semantic document type |
meta |
EnvelopeMeta |
empty model | Parser metadata |
payload |
InvoicePayload | GenericPayload |
— | Discriminated by kind |
EnvelopeMeta
Section titled “EnvelopeMeta”{ "cost_eur": 0.00037, "confidence": 0.97, "provider": "deepseek-v3", "prompt_version": "fattura-v1-a1b2c3d4" }| Field | Type | Default | Note |
|---|---|---|---|
cost_eur |
float | 0.0 |
Costo in EUR dell’elaborazione LLM |
confidence |
float | 1.0 |
Confidence score 0.0–1.0 (1.0 = deterministico) |
provider |
string | "" |
Provider LLM, vuoto per deterministico |
prompt_version |
string | "" |
Versione del prompt template |
InvoicePayload
Section titled “InvoicePayload”| Field | Type | Default | Description |
|---|---|---|---|
kind |
Literal["invoice"] |
"invoice" |
Discriminant |
dati_trasmissione |
dict[str, Any] |
{} |
FatturaPA transmission data |
cedente_prestatore |
dict[str, Any] |
{} |
Supplier data |
cessionario_committente |
dict[str, Any] |
{} |
Customer data |
corpi |
list[dict[str, Any]] |
[] |
Invoice line/body data |
I campi sono dict grezzi come trasportati dal parser: il payload NON normalizza
(fedeltà al dominio). extra="allow" garantisce compatibilità forward del JSONB.
GenericPayload
Section titled “GenericPayload”| Field | Type | Default |
|---|---|---|
kind |
Literal["generic"] |
"generic" |
content |
dict[str, Any] |
{} |
Discriminated union invariant
Section titled “Discriminated union invariant”Il payload è una Legal Union Pydantic v2 discriminata su kind:
DocumentPayload = Annotated[ InvoicePayload | GenericPayload, Field(discriminator="kind"),]Il backend enforce anche:
document_type == payload.kindUn mismatch viene rifiutato dal model validator. Questo è un invariant contrattuale, non una convenzione client-side.
Forward compatibility
Section titled “Forward compatibility”Entrambi i payload models usano extra="allow". Nuovi campi parser possono essere
trasportati senza rompere i consumer che leggono solo campi stabili. Aggiungere un nuovo
document_type richiede un nuovo payload model e un corrispondente branch nella union.
v1 migration
Section titled “v1 migration”I vecchi record v1 vengono upgradati on-read dal backend. Il wire contract corrente è v2 only.
Wrapper vs envelope
Section titled “Wrapper vs envelope”HTTP response└── ParseResponse ├── job_id / status ├── provider_used / prompt_version ├── confidence / cost_usd / tokens ├── content_hash └── result └── DocumentEnvelope v2 ├── schema_version ├── document_type ├── meta └── payloadParseResponse — il wrapper HTTP
Section titled “ParseResponse — il wrapper HTTP”| Campo | Tipo | Note |
|---|---|---|
job_id |
string | UUID del job |
status |
"done" | "failed" | "queued" |
Stato elaborazione |
document_type |
string | Tipo documento rilevato |
provider_used |
string | Provider LLM usato |
prompt_version |
string | Versione del prompt |
confidence |
float | null | Confidence score |
cost_usd |
float | Costo in USD |
tokens |
integer | Token consumati |
fallbacks |
string[] | Fallback attivati |
content_hash |
string | SHA-256 canonico |
result |
DocumentEnvelope | null |
Contenuto strutturato v2 |
error |
string | null | Messaggio errore |
DocumentResponse — upload wrapper
Section titled “DocumentResponse — upload wrapper”| Campo | Tipo | Note |
|---|---|---|
job_id |
string | UUID del job |
doc_type |
string | Tipo documento rilevato |
content_hash |
string | SHA-256 canonico |
size_bytes |
integer | Dimensione in byte |
mime_type |
string | MIME type rilevato |
deduplicated |
boolean | Cache hit |
status |
"done" | "requires_vision" | "queued" | "failed" | "expired" |
Stato |
message |
string | null | Messaggio contestuale |
La distinzione è netta: DocumentResponse descrive stato di ingestione, ParseResponse
trasporta il DocumentEnvelope v2 strutturato.