Salta ai contenuti

Endpoint

Sonda di liveness pubblica.

Terminal window
curl -s https://api.factum.pyragogy.org/health
{"status":"ok"}

Stato operativo pubblico. La risposta include versione del servizio, uptime e, quando il DB è raggiungibile, contatori dei job e informazioni aggregate sui costi.

Terminal window
curl -s https://api.factum.pyragogy.org/status

Carica un FatturaPA XML o una fattura PDF. L’endpoint restituisce metadata di ingestion; non restituisce l’envelope parsato in DocumentResponse.

Auth: X-API-Key (header).

Terminal window
curl -X POST 'https://api.factum.pyragogy.org/v1/uploads' \
-H 'X-API-Key: YOUR_API_KEY' \
-F 'file=@./invoice.xml;type=application/xml'

L’unico campo multipart è file. Il nome file è fornito come metadata multipart, non come campo separato.

Campo Tipo Descrizione
job_id string (UUID) ID del job per polling /v1/uploads/{job_id}
doc_type string Tipo rilevato (es. fattura_pa_xml, invoice_pdf, generic)
content_hash string SHA-256 del contenuto (whitespace-collapsed per XML)
size_bytes integer Dimensione file in byte
mime_type string MIME type rilevato
deduplicated boolean true se il documento era già processato (cache hit)
status enum done | requires_vision | queued | failed | expired
message string | null Messaggio contestuale (es. errore di validazione)

Per PDF, status è attualmente requires_vision e il messaggio rimanda a /v1/parse per l’estrazione semantica.

{
"job_id": "3f2b5e6a-0000-4000-8000-000000000004",
"doc_type": "fattura_pa_xml",
"content_hash": "a1b2c3d4e5f6...",
"size_bytes": 2841,
"mime_type": "text/xml",
"deduplicated": false,
"status": "done",
"message": null
}
Status Significato
400 File vuoto
401 X-API-Key mancante o non valida
413 Body/file supera il limite di 10 MiB (max_upload_bytes)
415 Tipo documento/content non supportato (non XML/PDF)
422 XML FatturaPA rilevato ma parsing deterministico fallito, PDF senza layer di testo (< 80 char), o PDF > 50 pagine
500 Errore imprevisto server/storage/database

Gli errori upload usano RFC 7807 application/problem+json.

Polling di un job upload.

Terminal window
curl -s 'https://api.factum.pyragogy.org/v1/uploads/JOB_ID' \
-H 'X-API-Key: YOUR_API_KEY'

Un job inesistente restituisce 404 come RFC 7807 application/problem+json.

La risposta rimane DocumentResponse; il DocumentEnvelope parsato non è incluso in questo modello di risposta.

Elabora un job caricato o un testo diretto. Lo schema backend è ParseRequest.

Auth: X-API-Key (header).

Importante: job_id e text sono XOR — esattamente uno dei due deve essere presente.

Campo Tipo Obbligatorio Descrizione
job_id UUID | null XOR con text Job ID da /v1/uploads
text string | null XOR con job_id Testo diretto. Zero-retention: mai su disco/DB
doc_type "auto" | "fattura" | "f24" | "generico" No (default: "auto") Hint di tipo documento
async_mode boolean No (default: false) true → 202 Accepted. Non valido con text
callback_url URL HTTPS | null No Webhook per async. Solo con async_mode=true

Vincoli di validazione (422):

  • text < 80 caratteri → rifiutato (layer di testo assente)
  • text > 200.000 caratteri → rifiutato (RIZZO_PII_MAX_TEXT_CHARS)
  • async_mode=true + text → 422 (testo è stateless, solo in RAM)
  • callback_url senza async_mode=true → 422
  • job_id e text entrambi presenti o entrambi assenti → 422 (XOR)
Terminal window
curl -X POST 'https://api.factum.pyragogy.org/v1/parse' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"text":"Fattura n. 2026/001 del 08/09/2026. Cedente: ACME S.r.l. (P.IVA IT01234567890), Via Roma 1, Milano. Cessionario: Beta S.p.A., Via Verdi 15, Torino. Totale documento: 1.220,00 EUR. Imponibile: 1.000,00 EUR. IVA 22%: 220,00 EUR.","doc_type":"auto","async_mode":false}'

Python · httpx

import httpx
payload = {
"text": "Fattura n. 2026/001 del 08/09/2026. Cedente: ACME S.r.l. (P.IVA IT01234567890), Via Roma 1, Milano. Cessionario: Beta S.p.A., Via Verdi 15, Torino. Totale documento: 1.220,00 EUR. Imponibile: 1.000,00 EUR. IVA 22%: 220,00 EUR.",
"doc_type": "auto",
"async_mode": False,
}
response = httpx.post(
"https://api.factum.pyragogy.org/v1/parse",
headers={"X-API-Key": "YOUR_API_KEY"},
json=payload,
)
response.raise_for_status()
print(response.json())

TypeScript · fetch

// Sostituisci con la tua chiave API
const API_KEY = "YOUR_API_KEY";
const response = await fetch("https://api.factum.pyragogy.org/v1/parse", {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "Fattura n. 2026/001 del 08/09/2026. Cedente: ACME S.r.l. (P.IVA IT01234567890), Via Roma 1, Milano. Cessionario: Beta S.p.A., Via Verdi 15, Torino. Totale documento: 1.220,00 EUR. Imponibile: 1.000,00 EUR. IVA 22%: 220,00 EUR.",
doc_type: "auto",
async_mode: false,
}),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const result = await response.json();

Go · net/http

package main
import (
"bytes"
"fmt"
"net/http"
)
func main() {
body := []byte(`{"text":"Fattura n. 2026/001 del 08/09/2026. Cedente: ACME S.r.l. (P.IVA IT01234567890), Via Roma 1, Milano. Cessionario: Beta S.p.A., Via Verdi 15, Torino. Totale documento: 1.220,00 EUR. Imponibile: 1.000,00 EUR. IVA 22%: 220,00 EUR.","doc_type":"auto","async_mode":false}`)
req, _ := http.NewRequest("POST", "https://api.factum.pyragogy.org/v1/parse", bytes.NewReader(body))
req.Header.Set("X-API-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer res.Body.Close()
fmt.Println(res.Status)
}

PHP · cURL

<?php
$apiKey = 'YOUR_API_KEY'; // Sostituisci con la tua chiave
$ch = curl_init('https://api.factum.pyragogy.org/v1/parse');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'text' => 'Fattura n. 2026/001 del 08/09/2026. Cedente: ACME S.r.l. (P.IVA IT01234567890), Via Roma 1, Milano. Cessionario: Beta S.p.A., Via Verdi 15, Torino. Totale documento: 1.220,00 EUR. Imponibile: 1.000,00 EUR. IVA 22%: 220,00 EUR.',
'doc_type' => 'auto',
'async_mode' => false,
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
if ($response === false) throw new RuntimeException(curl_error($ch));
curl_close($ch);
echo $response;
Terminal window
curl -X POST 'https://api.factum.pyragogy.org/v1/parse' \
-H 'X-API-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"job_id":"3f2b5e6a-0000-4000-8000-000000000004","doc_type":"auto","async_mode":false}'
{
"job_id": "3f2b5e6a-0000-4000-8000-000000000004",
"doc_type": "fattura",
"async_mode": true,
"callback_url": "https://example.com/factum/callback"
}
Campo Tipo Descrizione
job_id string UUID del job
status "done" | "failed" | "queued" Stato elaborazione
document_type string Tipo documento rilevato (es. "fattura")
provider_used string Provider LLM ("deepseek-v3", "gpt-4o-mini", "")
prompt_version string Versione del prompt template
confidence float | null Confidence score 0.0–1.0 (1.0 = deterministico)
cost_usd float Costo LLM in USD (0.0 per deterministico)
tokens integer Token LLM consumati
fallbacks string[] Fallback LLM attivati
content_hash string SHA-256 canonico del documento
result DocumentEnvelope | null Contenuto strutturato v2 (null su errore)
error string | null Messaggio errore se status: failed
{
"job_id": "3f2b5e6a-0000-4000-8000-000000000004",
"status": "done",
"document_type": "invoice",
"provider_used": "fast-path",
"prompt_version": "fast-path-v1",
"confidence": 1.0,
"cost_usd": 0.0,
"tokens": 0,
"fallbacks": [],
"content_hash": "a1b2c3d4...",
"result": {
"schema_version": "2.0",
"document_type": "invoice",
"meta": {
"confidence": 1.0,
"provider": "fast-path",
"prompt_version": "fast-path-v1"
},
"payload": {
"kind": "invoice",
"dati_trasmissione": {},
"cedente_prestatore": {},
"cessionario_committente": {},
"corpi": []
}
},
"error": null
}

result è null in caso di errore. Il testo diretto è stateless: non crea un ParseJob.

Status Significato
401 X-API-Key mancante o non valida
404 job_id referenziato inesistente
422 Sorgente non valida (violazione XOR), limiti text (< 80 o > 200K char), estrazione rifiutata
500 Errore imprevisto parsing/provider/sidecar privacy
503 Sidecar Rizzo non raggiungibile; fail-closed

DocumentResponse e ParseResponse non sono intercambiabili. La prima descrive lo stato di ingestion; la seconda trasporta il DocumentEnvelope v2 strutturato quando il parsing produce un risultato.

Webhook per la gestione self-service delle licenze Lemon Squeezy. L’endpoint non richiede autenticazione API key; la firma HMAC-SHA256 nel header X-Signature funge da autenticazione implicita.

Non genera documentazione requestBody in OpenAPI (usa request: Request di Starlette/FastAPI per leggere il body raw, necessario per la verifica HMAC).

Evento Azione
subscription_created Crea chiave API (status: active)
order_created Crea chiave API (status: active)
subscription_updated Aggiorna tier e rate limit
subscription_cancelled Revoca chiavi (status: revoked)
subscription_expired Revoca chiavi (status: revoked)
subscription_resumed Riattiva chiavi (status: active)
Tier Limite
starter 60 richieste/minuto
pro 300 richieste/minuto
custom 1000 richieste/minuto
Terminal window
# Simula un evento subscription_created
LEMON_SECRET="your_webhook_secret"
PAYLOAD='{"meta":{"event_name":"subscription_created"},"data":{"attributes":{"user_email":"user@example.com","variant_name":"starter","first_subscription":{"license_key":{"key":"ls_xxxxxxxxx"}}}}}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$LEMON_SECRET" | awk '{print $2}')
curl -X POST 'https://api.factum.pyragogy.org/v1/webhooks/lemonsqueezy' \
-H 'Content-Type: application/json' \
-H "X-Signature: $SIGNATURE" \
-d "$PAYLOAD"
Status Significato
200 Evento processato (anche se ignorato)
400 Payload JSON non valido
401 Firma HMAC mancante o non valida
503 LEMONSQUEEZY_WEBHOOK_SECRET non configurato
{
"status": "created",
"subscription_id": "sub_xxxxxxx",
"api_key": "factum_xxxxxxxxxxxxxxxxxxxx"
}