TaxHarvest API

Sistema RAG per il diritto italiano ed europeo + UAE. Ricerca ibrida (vector HNSW + FTS + reranker) su 648.000+ documenti normativi e giurisprudenziali italiani + UE + UAE + internazionali, sintesi con pipeline anti-hallucination 9-stage, 65 codici indicizzati article-by-article, 67 fonti auto-scraping (61 IT + 6 UAE).

Production status — v25.110 (1 giu 2026) Sistema in steady state. Pipeline anti-allucinazione a 9 stage attiva (Meta-handler → Tool routing → Retrieval → Abstention → LLM → Citation Guard → LLM Judge V2 → Re-prompt → Factuality soft flag). Slug Normattiva allineati 1:1 con DocZoom Studio CODES_CATALOG (58 codici). UAE corpus separato (836 docs, Voyage-3-large 1024d, country isolation). 18 moduli totali (10 IT per materia + 3 IT per profilo professionale + 5 UAE).

Stats live (20 mag 2026)

MetricValue
Total documents648.000+ (IT) + 836 (UAE)
Total chunks3.92M IT (pgvector HNSW 1536d) + 28K UAE (Voyage 1024d)
Fonti distinte67 (61 IT + 6 UAE, auto-scrape via scheduler 1×/day)
Codici Normattiva art-by-art65 codici / 14.963 articoli
Moduli macro-area Lexroom-style18 moduli (10 IT per materia + 3 IT per profilo professionale + 5 UAE)
Atti UE EUR-Lex indicizzati38 (GDPR, AI Act, NIS 1/2, DORA, MiCAR, PSD2, AMLD 4-6, ATAD, DAC, eIDAS, ecc.)
Cassazione336.000+ sentenze (civile + penale + costituzionale)
Giustizia Amministrativa269.000+ provvedimenti (TAR 30 sedi + CdS + CGA)
Citation hallucination rate~1% post Citation Guard + LLM Judge V2 + Re-prompt
Latency p5015-25s end-to-end (/answer) · ~100ms (cache hit) · ~1-5s su /query (~700ms UAE)
Eval coverage305 query golden / 11 dataset / 7 profili (legacy) + 2.250 query / 15 moduli (baseline v25.101)

Base URL

https://bancadati.doczoom.ai

Quick start (cURL)

curl -X POST https://bancadati.doczoom.ai/api/doczoom/answer \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "Soglia forfettario 2026?", "top_k": 10}'

UI standalone disponibili

RouteCosa è
/Monitor live + chat playground
/api-docsQuesta pagina (API documentation)
/docsSwagger UI auto-generato
/redocReDoc UI alternativo
/alertsNorm Alerts dashboard (v25.101): subscribe a fonti/moduli/keyword, vedi eventi
/benchmark🆕 Modules Baseline Benchmark (v25.102): drill-down su 2.250 query baseline per 15 moduli
/graphKnowledge graph ontologico (50 concetti)
/doc/{id}📄 Document viewer (v25.109): lettore pubblico del testo completo di un documento. Target consigliato del bottone "Apri fonte" — risolve i link non-deep-linkabili (es. SPA ItalGiure #id=... che obbliga a reinserire il codice della sentenza). Vedi campo viewer_url nelle response. v25.110: bottone ScaricaGET /doc/{id}/download?format=pdf|docx (PDF o Word formattati in stile DocZoom).

Recent updates

  • v25.115 (1 giu 2026): Entity-match SQL disattivato (retrieval più veloce) — A/B test: lo stadio entity-match contribuiva 0 chunk ai risultati finali, aggiungeva 8-27s di latenza e rompeva il reranker Voyage. Disattivato (la NER resta attiva per entities_found). Moduli pesanti come consulente-lavoro da ~28s a ~2s.
  • v25.114 (1 giu 2026): Audit 67 fonti + 15 moduli · recall "Per fonte" + pulizia corpus — testate tutte le fonti e i moduli esposti. Rimosse dal picker corte_costituzionale (3.808 doc erano pagine di blocco anti-bot, non sentenze — purgati) e dogi (0 doc) → GET /api/sources ora ritorna 67 fonti utili. Ricerca filtrata per fonte: per filtri selettivi (≤ 10.000 doc) la NN ora è esatta within-source (recall perfetto, risolve fonti di nicchia che potevano tornare 0 risultati); le mega-fonti restano su HNSW.
  • v25.113 (1 giu 2026): statement_timeout sulla ricerca vettoriale — tetto di 60s (env VECTOR_SEARCH_TIMEOUT_S) sulle query vettoriali: una query cold che sfora viene troncata e degrada con grazia (l'API abstiene) invece di causare timeout/saturazione pool.
  • v25.112 (1 giu 2026): Fix indice HNSW (ricerca filtrata 10-40× più veloce) — le query filtrate per modulo/fonte ora usano correttamente l'indice HNSW (era ignorato per un mismatch di predicato sull'indice parziale): da 32-85s a 0,2-6s a regime.
  • v25.110 (1 giu 2026): ⬇ Download PDF / Word dal viewer /doc/{id} — nuovo bottone "Scarica" (stile Glass, dropdown no-JS) nel lettore: GET /doc/{id}/download?format=pdf oppure ?format=docx. Il documento viene generato server-side con la formattazione del design system DocZoom (titolo serif editoriale, accento clay, intestazione con estremi + metadati, corpo giustificato, footer con fonte ufficiale + disclaimer + rif., paginazione per le sentenze lunghe). PDF via reportlab, Word via python-docx. Pubblico (no API key), come il viewer.
  • v25.109 (31 mag 2026): 📄 Document viewer /doc/{id} + campi viewer_url/doc_id nelle response — fix UX sulle fonti Cassazione. Il link che davamo all'utente era la SPA ItalGiure https://www.italgiure.giustizia.it/sncass/#id=<solr_id>: un hash-fragment client-side che NON fa deep-link → l'utente atterrava sulla maschera di ricerca e doveva reinserire a mano il codice della sentenza (~340K sentenze, ~100% del corpus Cassazione). Dal Solr scarichiamo solo il testo OCR (nei chunks), non il PDF.

    Soluzione: nuovo lettore pubblico GET /doc/{id} (no API key, contenuti legali pubblici) che ricostruisce il testo completo dai chunks (de-overlap), con intestazione ufficiale (es. Corte di Cassazione · Sez. III · Sent. n. 18633/2026, Pres./Rel.) e link alla fonte ufficiale in fondo. Le response di /query, /answer, /retrieve-legal e /reference ora espongono per ogni source doc_id + viewer_url (es. https://bancadati.doczoom.ai/doc/665989): url resta la fonte ufficiale, usa viewer_url come target del bottone "Apri fonte". Funziona per tutte le fonti (Cassazione, Normattiva, AdE, UAE, …). Aggiunto indice idx_documents_url per il lookup batch url→id.
  • v25.105 (25 mag 2026): ⚡ Fast-path jurisprudence lookup (200ms vs 43s) + fix "cassa→imprese minori" bug — bug critico rilevato: query "Cass. 11431/2026" non ritornava la sentenza pur essendo in DB. Cause: (1) la substring "cassa" dentro "Cassazione" triggerava espansione errata cassa→imprese minori; (2) doc_ref_patterns in rag.py copriva solo prassi AdE + leggi, nessun pattern per Cassazione/TAR/CdS/Corte Cost; (3) hybrid search impiega 41-170s su 3.92M chunks → watchdog 40s skip rag.multi_search → reference matching mai applicato.

    Fix applicati: (1) Discriminazione cassa vs Cassazione: se query contiene \bcassazion[ie]\b o \bcass\. o \bcass\s+(pen|civ|cost|sent|ord|sez|s\.u\.), skip cassa da fiscal_terms + concept_thresholds. (2) Estesa doc_ref_patterns con 4 nuovi regex (cassazione, tar, cds, corte_cost) + source_filter applicato in SQL. (3) NEW: Jurisprudence fast-path in /api/doczoom/query: PRIMA di hybrid, verifica match regex sentenza/numero/anno; se sì, SQL diretto su title + source = ANY(...) → return immediato con top_score=1.0, shortcut=jurisprudence_lookup, latency 200-250ms (vs 43-170s precedente). Pattern coperti: Cass. 11431/2026, Cassazione Penale Ordinanza n. 11432/2026, TAR Roma 12345/2024, CdS 1234/2024, Corte Cost. 209/2022.

    Verifica live: query "Cass. 11431/2026" ora ritorna in 237ms con top_score=1.0, top chunk = "Cassazione Penale Ordinanza n. 11431/2026" (doc 81817).
  • v25.104 (20 mag 2026): ⚖️ 13 endpoint giurisprudenza dedicati + fix bug authority filter — aggiunto shortcut REST per ogni fonte giurisprudenziale: /api/cassazione (336K), /api/cassazione/{n}/{anno} (lookup), /api/tar (242K), /api/consiglio-stato (20K), /api/corte-costituzionale (3.8K), /api/cgue (1.4K), /api/cedu, /api/giustizia-tributaria, /api/abf, /api/agcm, /api/agcom, /api/sentenze-uae (102), /api/adgm (80), /api/difc (22). Inoltre fix bug /api/legal-judgments?authority=…: il parametro veniva ignorato e tornava sempre giustizia_amministrativa. Ora authority è documentato + mappato su _AUTHORITY_MAP (20 slug supportati) + risposta espone sources_searched per trasparenza. _JUDGMENT_SOURCES_IT esteso da 5 a 15 fonti (aggiunte CGUE, CEDU, ABF, AGCM, AGCOM, ANAC, Banca Italia, IVASS, Consob, EPO BoA — prima invisibili al browsing).
  • v25.103 (20 mag 2026): 👔 3 moduli "per profilo professionale" (commercialista, tributarista, consulente-lavoro) — estensione di modules.yaml con 3 macro-moduli pensati per selezione rapida nel picker Studio. Coesistono con i 10 moduli per materia (Civile, Tributario, Penale…) e con le 66 collections L1-L3 (per profili granulari). Esempio uso: commercialista → modulo macro generalista (fiscale + societario + bilancio + lavoro base); tributarista → focused su contenzioso tributario + penale tributario; consulente-lavoro → lavoro + previdenza + sicurezza + immigrazione. Totale moduli ora: 18 (10 IT materia + 3 IT professione + 5 UAE). GET /api/modules e filtro modules=[…] in /answer//query li espongono nativamente.
  • v25.102 (20 mag 2026): 📊 Modules Baseline Benchmark + UI /benchmark — eseguito retrieval-only benchmark sui 15 moduli (10 IT + 5 UAE), 150 query × modulo = 2.250 query totali in 9h41m. Findings principali: UAE cluster 0.752-0.778 con 100% success rate (Voyage-3-large 1024d top quality); IT range 0.500 (ip, gap corpus reale) → 0.850 (penale, reference matching codificato). Mean IT 0.636 vs Mean UAE 0.770 → conferma valore upgrade embedding IT. Nuova UI drill-down con tutte le 2.250 query visibili, filtri search/diff/conf, sort multi-colonna. Risultati in eval/results/baseline_20260519_224355/. Costo run: ~$0.45.
  • v25.101 (20 mag 2026): 📡 Norm Alerts + scheduler harmonization 1×/day + 11 sub-collections + api-docs full audit — nuova feature notifiche normative (8 endpoint + UI standalone): 6 sub_type (source/module/collection/keyword/reference/country), scan-on-poll architecture, backfill 7-day per UX iniziale. Scheduler ricalibrato da 38 a 59 entry, ognuna 1×/day spread su 24h UTC (aggiunte 26 fonti IT precedentemente non-scheduled). 11 sub-collections L3 nuove (7 commercialista + 4 tributarista). Full audit api-docs 2026-05-20: 12 drift fixati (12 endpoint nuovi documentati, /answer parameter table espansa 4→11 campi, architecture diagram 6→9 stage, numeri 215K→648K docs, version drift v25.86→v25.100).
  • v25.100 (18 mag 2026): 🔗 Slug allineati DZ CODES_CATALOG (fix codici "non trovati") — estesa IT_UI_METADATA da 16 a 58 codici per coprire l'intera hardcoded CODES_CATALOG di doczoom-studio. Bug pre-v25.100: per i 48 codici non in IT_UI_METADATA, l'endpoint auto-generava slug lunghi (es. preleggi-disposizioni-sulla-legge-in-generale), ma DZ ha findCodeBySlug hardcoded che cerca preleggi breve → empty state nella detail page. Ora gli slug TaxHarvest matchano 1:1 quelli DZ: preleggi, jobs_act, tu_espropriazioni, cod_pari_opportunita, tu_immigrazione, cod_antimafia, ecc. Restano 6 codici minori in TaxHarvest ma non ancora in DZ CODES_CATALOG (testo-unico-infortuni-lavoro-dpr-1124-1965, ordinamento-giurisdizione-tributaria, ecc.) — questi sono "extra" che DZ può aggiungere quando vuole.
  • v25.99 (18 mag 2026): 📖 /api/legal-codes DZ drop-in + UAE document detail fix — refactor di /api/legal-codes per matchare lo shape che il frontend DocZoom già usa per CODES_CATALOG hardcoded: {slug, name, shortName, description, category, articles, taxharvestSource, taxharvestCategory}. Eliminata la necessità di hardcoding lato DZ: const catalog = (await fetch(...)).categories è drop-in con il map/filter esistente.
    Per country=IT: 64 codici Normattiva con UI metadata curated per i 16 core (CC, CPC, CP, CPP, TUIR, TUF, TUB, IVA, Statuto Contribuente, CCII, Cod. Assicurazioni, Cod. Consumo, Costituzione, ecc.). Per country=AE: 4 catalog entries (DIFC Laws 144 · ADGM Regulations 57 · CBUAE Federal Decree-Laws 190 · FTA Public Clarifications 343).
    Fix critico: GET /api/document/{id} ora legge da chunks_uae (Voyage 1024d) per docs UAE invece di chunks. Drawer DocZoom mostra correttamente full_text per leggi UAE (es. DIFC Arbitration Law → 44 chunks, 59.5K char).
  • v25.98 (18 mag 2026): 📖 /api/legal-codes + /api/legal-judgments (country-aware) — 2 nuovi endpoint per le tab "Codici" e "Sentenze" di DocZoom. Country-aware (IT/AE), stessa shape per entrambi i paesi. Eliminano l'hardcoding lato frontend (CODES_CATALOG IT-only, sources=['cassazione'] fisso).
    GET /api/legal-codes?country=IT → 64 codici Normattiva.
    GET /api/legal-codes?country=AE → 734 voci (DIFC Laws + ADGM Regulations + CBUAE Federal Decree-Laws + FTA Guides).
    GET /api/legal-judgments?country=AE → 102 judgments (80 ADGM + 22 DIFC) con court/year/case_number/parties parsed on-the-fly da slug.
    GET /api/legal-judgments?country=IT&court=Cassazione&year=2025 → filter su 336K sentenze IT con paginazione. UAE judgment parsing: slug pattern ADGM-ADGMCFI-2025-262{court:"ADGM CFI", year:2025, case_number:"ADGMCFI-2025-262", parties:["X","Y"]}.
  • v25.97 (18 mag 2026): 🔍 GET /api/sources enriched — risposta ora include per ogni source: country (IT/AE), doc_count (live count), modules (lista moduli di appartenenza), registered_scraper (bool). Nuovi query params ?country=IT|AE|all e ?module={id} per filtering server-side. Permette a DocZoom di mostrare il picker fonte-singola filtrato per paese o modulo senza enumerare lato client. Backward compat preservata: chiave "sources" rimane lista di stringhe per i client v1.
  • v25.96 (18 mag 2026): 📚 Modules full coverage audit — 0 codici orfani — audit completo del corpus 67 fonti / 64 codici normattiva. Pre-audit: 5 sources orfane (gazzetta_ufficiale, eur_lex, eurlex, eiopa, istat) + 28 codici normattiva orfani + 3 cassazione macro_area orfani. Post-audit: SOLO istat (2 docs, marginale) escluso. Aggiunti cross-cut gazzetta_ufficiale + eur_lex + eurlex a tutti i 10 moduli IT. Aggiunti 13 codici genuinamente mancanti (Cod. Assicurazioni Private, CAD, Antimafia, CPP Minorile, TU Pubblico Impiego, Cod. Terzo Settore, ecc.). Fix 10+ string-mismatch alias (DB "Codice del Processo Tributario" vs YAML "Processo tributario"). Coverage doc-count post-fix: amministrativo 110K→285K, privacy 600→11K, lavoro 12K→33K, bancario 6K→26K. Nuovo endpoint GET /api/countries per Settings DocZoom (lista paesi + statistiche, no hardcoding). Benchmark discriminazione: 13/44 primary > distractor (+3 vs v25.95), 0 risposte identiche.
  • v25.95 (18 mag 2026): 📚 Module filter sub-source granularità — metadata-aware predicate (cassazione macro_area + normattiva codice) applicato pre-truncation. Internal top_k boost (×3, cap 60) per assorbire i drop. Batch SQL enrichment per i record da reference/article match che non portano doc_metadata. Case-insensitive match. "Untagged fallback" per le 199K cassazione storiche senza macro_area (recall > precision). Live discrimination verified: licenziamento → lavoro=1, tributario=2, civile=0; GDPR art 6 → privacy=1, civile/lavoro/tributario=0; accertamento DPR 600 → tributario=4, civile/lavoro=0.
  • v25.94 (18 mag 2026): 🇦🇪 +5 moduli UAE + cross-country validator — aggiunti 5 moduli UAE (uae-tax, uae-banking-amlcft, uae-difc, uae-adgm, uae-common-law) che si applicano alla pipeline UAE isolata (Voyage-3-large + chunks_uae). Aggiunto campo country: IT|AE a ogni modulo nel YAML, e validator cross-country in /api/doczoom/query: se i moduli scelti appartengono a un country diverso da quello del request → HTTP 400 module_country_mismatch. Nuovo query param ?country=IT|AE|all su GET /api/modules. Totale moduli ora: 15 (10 IT + 5 UAE).
  • v25.93 (18 mag 2026): 📚 10 moduli macro-area Lexroom-style — nuovo sistema di filtraggio per macro-area giuridica cross-source. Definiti 10 moduli (diritto-civile, diritto-tributario, privacy-data-protection, diritto-bancario, diritto-del-lavoro, diritto-societario, diritto-di-famiglia, diritto-amministrativo, ip-proprieta-intellettuale, diritto-penale) in modules.yaml. Ogni modulo è una lista di filtri (source + metadata predicate, es. cassazione.macro_area="tributario", normattiva.codice="TUIR"). Nuovi endpoint: GET /api/modules + GET /api/modules/<id> con live doc_counts per source. Nuovo body field modules: list[str] su POST /api/doczoom/query. Defensive post-filter garantisce che chunks non appartenenti al modulo vengano droppati prima della response. Differenza da collections: moduli = macro-aree pure (giuridiche), collections = profili professionali / temi commerciali. Possono coesistere.
  • v25.92 (18 mag 2026): 🇦🇪 UAE final: FTA round 2 completato (522→836 docs) — FTA Public Clarifications cresciuto da 29→343 docs / 622→8.988 chunks dopo secondo bootstrap (timeout 5h, finito in 27min). Pipeline OCR ha gestito bulletins VAT/CT/Excise rasterizzate. 34 PDF rifiutati (text vuoto / ZIP files erroneamente serviti come PDF). UAE corpus finale: 836 docs / 28.379 chunks su 6 sources. Restano bloccate solo eLaws (TCP IP block) e FSRA (text empty upstream).
  • v25.91 (18 mag 2026): 🇦🇪 UAE full PDF coverage (413→522 docs, 6/8 sources) — ADGM-Courts (80 docs / 2.976 chunks via OCR Tesseract) + FTA Public Clarifications (29 docs / 622 chunks) importati. ADGM-Courts ha 146 Print-to-PDF judgments rasterizzati, processati in 38 min totali (vs stima 10-20h: cap 30 pp/PDF a DPI 120 sufficiente per la maggior parte dei judgments). Test live retrieval OK su tutti 6 sources con top scores 0.74-0.80. FTA round 2 in BG (5h timeout) per i 126 bulletins rimanenti.
  • v25.90 (18 mag 2026): 🇦🇪 UAE corpus expansion (212→413 docs) — nuovo common/pdf_extract.py in legal-sources-overlay/: pipeline a 3 livelli pypdfium2 streaming → pdfplumber fallback → Tesseract OCR (poppler + pytesseract) per PDF rasterizzati. Cap OCR a 30 pp/PDF + DPI 120 per limitare tempi. Cache PDF a /tmp/uae_pdf_cache/<sha256>. Nuove fonti importate: uae_adgm_legislation (57 docs / 2K chunks — ADGM Courts Regulations + Abu Dhabi laws) + uae_difc_legislation (144 docs / 9.7K chunks — DIFC Arbitration / Common Reporting / Companies / Contract Law). Container taxharvest-api memory bumped 2→4G dopo OOM kill durante Voyage multiprocessing embed. FTA + ADGM-Courts in overnight OCR.
  • v25.89 (18 mag 2026): 🇦🇪 UAE corpus + country isolation — nuovo param country ISO-2 (default ["IT"], opzionale ["AE"]) su /api/doczoom/query. Tabella separata chunks_uae con embedding Voyage-3-large 1024d (legal-domain). Import iniziale: 190 docs CBUAE (AML/CFT, Federal Decree-Laws, regolamenti) + 22 DIFC Courts judgments. Pipeline UAE: voyage embed → HNSW search → top-K, p50 500ms. Validazione fail-fast: country diverso da IT/AE → HTTP 400 unsupported_country. Roadmap: FTA Public Clarifications, ADGM Courts/Legislation, DIFC Legislation, eLaws (PDF extractor in dev).
  • v25.86 (14 mag 2026): +30 sub_area routing per /retrieve-legal — 7 practice_areas / 42 routings totali. Coverage istituti civili (compravendita, mutuo, fideiussione, locazione comm./abit., mandato, comodato, appalto, assicurazione, donazione, successioni, condominio, revocatoria, resp. EC), lavoro (mobbing, trasferimento azienda), tributario (accertamento, contenzioso, IVA), penale (reati tributari, bancarotta, 231), amministrativo (urbanistica, concorrenza), corporate (cessione SRL, op. straordinarie, DD M&A), privacy (GDPR compliance, data breach). Nuovo endpoint GET /api/doczoom/practice-areas espone tassonomia live.
  • v25.83: meta-handler conservativo — solo saluti + identita. Drop falsi positivi su query legali con "costi" / "privacy".
  • v25.80: /retrieve-legal con must_include anchor, authority_mix, MMR diversity, score_breakdown, exclude_authorities, validation fail-fast HTTP 400.
  • v25.77: nuovo endpoint /retrieve-legal con practice_area routing.
  • v25.74 (mag 2026): 15 nuove fonti EU + IT + intl (+928 docs) — EBA, EIOPA, ESMA, AMLA, FSB, IASB, BIS BCBS, UIF, AgID, IVASS, INAIL, MLPS, ANAC, ADM, ARERA.
  • v25.66: pulizia metadata XML residui in chunks di sentenze TAR/CdS, miglior qualità retrieval su modulo amministrativo.
  • v25.55-60: supporto query in inglese su atti UE (GDPR / AI Act / NIS / EPO / HUDOC) con risposta nella stessa lingua. Fix parser Solr Cassazione (text/plain content-type).
  • v25.43-54: 6 nuovi scraper — Borsa Italiana regolamenti, EPO Boards of Appeal Case Law 2025, HUDOC CEDU landmark v Italy, Negoziazione Assistita art-by-art, AGCM bollettini settimanali. Privacy boost: EDPB, atti UE Cyber/Data Act, TRIPS WTO, Convenzione Aja, CEDU IT. EUR-Lex 38 atti art-by-art.
  • v25.36-42: NIS 2 + DORA + GDPR + CNF Codice Deontologico + Convenzione ONU Diritti Fanciullo indicizzati art-by-art. cassazione_macro_aree applicate ai moduli L1 (riduzione rumore). 14 nuovi moduli L1 (Lexroom-style) in collections.yaml.
  • v25.18-35: pipeline anti-allucinazione 9-stage (Citation Guard + LLM Judge V2 + Re-prompt automatico + factuality soft flag). Hallucination rate residuo ~1%. Endpoint /api/doczoom/articles per fetch deterministico articoli. Flag prefer_speed=true per skip re-prompt (latency ridotta). collections param su /answer per pre-filter retrieval domain-specific.

Authentication

Tutti gli endpoint richiedono una API key passata nell'header X-API-Key. Le richieste senza key valida ricevono 401 Unauthorized.

X-API-Key: th_live_xxxxxxxxxxxxxxxxxxxxxxxx
Demo key per testing Per integrazione in dev/staging puoi usare taxharvest-demo-2026. In produzione richiedi una chiave dedicata via email.

Architecture

Ogni chiamata /api/doczoom/answer attraversa una pipeline a 9 stage con macchina anti-allucinazione (Citation Guard + LLM Judge V2 + Re-prompt automatico + Factuality soft flag). Latency p50 15-25s end-to-end (cache hit ~100ms). Per pipeline retrieval-only (/api/doczoom/query): 1-5s IT, 500-800ms UAE.

0Cache Redis — TTL 10 min. Cache hit = ~100ms (response immediato)
1Meta-query handler — Regex su 6 categorie (saluti, fonti, identità, costi, privacy, LLM) + LLM fallback (Gemini Flash Lite) per ambiguità. ~50-1900ms. Bypassa retrieval su meta-query.
2Tool routing — Detection P.IVA/CF/cambio valuta → tool autoritativo (VIES, Banca d'Italia). ~1-2s. No LLM se match tool.
3Hybrid retrieval — Vector HNSW (pgvector) + FTS italiano + LIKE trigram + Reference match + Article match + Multi-query expansion. Short-circuit aggressivo se hybrid ha già top_k risultati. ~2-6s. (v25.115: entity-match SQL disattivato — 0 contributo ai risultati, +8-27s latenza; la NER resta attiva per il campo entities_found.)
4Abstention check — Top-3 chunks max relevance < 0.30 → "Info insufficiente" + redirect fonte ufficiale. No LLM call.
5LLM synthesis — System prompt anti-hallucination + temp 0.0 + max_tokens 4096. Grounding sui chunks recuperati. ~15-25s.
6Citation Guard — Regex su Cass./CdS/TAR/Cost. + AdE circolari/risoluzioni/interpelli + INPS. DB lookup contro tabelle reali. STRIP citazioni inesistenti dal testo. ~50ms.
7LLM Judge V2 — Gemini Flash Lite con dossier strutturato (citazioni verified/removed + chunks top-3 + risposta evidenziata). Verdetto OK/ISSUE. ~1.8s.
8Re-prompt automatico — Se Judge V2 = ISSUE → rilancia LLM con istruzioni esplicite di rimozione elementi non grounded. 1 retry max. +15-25s su ~10-20% delle query.
9Factuality soft flag + Audit — Regex su numeri/date/circolari trovati nei chunks. Se ≥2 fatti non groundati → needs_verification=true (soft, no blocco). Audit log PostgreSQL fire-and-forget.

Note: gli stage 0-2 sono fast-path (bypassano retrieval/LLM se applicabili). Lo stage 6 (Citation Guard) opera prima del Judge V2 per ridurre falsi positivi. Lo stage 9 (Factuality soft flag) usa lo stesso fact extractor del Citation Guard ma come segnale all'utente, non come blocco. Pipeline retrieval-only (/api/doczoom/query) salta stage 5-9 (no LLM).

Componenti

LayerTecnologiaScopo / config
Embeddings ITtext-embedding-3-small (OpenAI, 1536d)Vector search HNSW chunks
Embeddings UAEvoyage-3-large (Voyage, 1024d)Vector search HNSW chunks_uae (country isolation)
Vector indexpgvector HNSW (m=16, ef_construction=64)O(log n) nearest-neighbor + iterative_scan strict_order
FTSPostgreSQL tsvector italiano + GIN trigramLexical match con highlighting
Rerankervoyage rerank-2.5-lite (Voyage)Cross-encoder top-50 → top-10. Free 12 mesi (200M token quota). Fallback merge order su 429.
Query rewritegemini-3.1-flash-lite-preview via OpenRouterEspansione naturale + load smoother. Redis cache TTL 1h. Kill switch REWRITER_DISABLED=true.
LLM synthesisConfigurabile via OPENROUTER_MODEL env (default qwen/qwen3-235b-a22b)Risposta finale con temp 0.0, max_tokens 4096
LLM judge factualitygemini-3.1-flash-lite-preview via OpenRouterVerdetto OK/ISSUE con dossier strutturato (chain-of-thought max_tokens 400)
Meta-handler LLM fallbackgemini-3.1-flash-lite-preview (stage-2)Solo per query non-legali ambigue. Skip se segnali legali nel query.
DatabasePostgreSQL 16 + pgvector + GIN FTS + trigram3.92M chunks IT + 28K UAE indicizzati
CacheRedis 7TTL 10 min /answer · 1h rewriter · 10 min rerank
Anti-hallucinationCitation Guard + LLM Judge V2 + Re-prompt + Factuality flag~1% hallu residue post pipeline (vs ~17% pre-guardrails)

Errors & Rate limits

Risposte di errore in formato JSON con campi error e detail.

StatusSignificatoAzione
200OKSuccesso
401API key mancante o invalidaVerifica header X-API-Key
429Rate limit superatoDefault 60 req/min per IP. Riduci frequenza
500Errore server internoRiprova; se persiste apri ticket

Rate limit

Default 60 richieste/minuto per IP. Per limiti più alti contatta il team.

DocZoom Answer

End-to-end RAG: retrieval ibrido + cross-encoder rerank + LLM synthesis. Restituisce una risposta sintetica + lista fonti citabili. Endpoint principale per il frontend DocZoom.

POST /api/doczoom/answer

Request body

FieldTypeRequiredDescription
querystringrequiredDomanda dell'utente (max 2000 char).
top_kintegeroptionalNumero chunk passati al LLM. Default 10, range 1–25.
sourcesstring[]optionalFiltro fonti specifiche (es. ["normattiva","ade_circolari"]). Unione con collections e modules se forniti.
collectionsstring[]optionalFiltro collections professionali (es. ["commercialista-iva","tributarista-accertamento"]). Vedi GET /api/collections.
min_relevancefloatoptionalSoglia minima score reranker. Default 0.3, range 0.0–1.0. Sotto soglia → abstention.
document_contextstringoptionalTesto di un documento caricato dall'utente (contratto, bilancio, ecc.). Massimo 100K char. Iniettato nel system prompt come contesto aggiuntivo per analisi.
document_namestringoptionalNome del file caricato (per citazione nel prompt).
profilestringoptionalProfilo professionale per tuning prompt (es. "Commercialista", "Avvocato Tributarista"). Influenza tono e priorità citazioni.
materiastringoptionalMateria giuridica (es. "IVA", "Diritto societario"). Influenza routing e boost di source pertinenti.
prefer_speedbooleanoptionalDefault false. Se true: timeout aggressivi + skip re-prompt + skip multi_search. Per UX real-time, accetta -5% kw recall.
max_output_tokensintegeroptionalDefault 4096 (regola cardinale, non ridurre senza motivo). Range 100-8192. Per risposte brevi su query semplici.

Example request

curl -X POST https://bancadati.doczoom.ai/api/doczoom/answer \
  -H "X-API-Key: $TAXHARVEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Qual è la soglia forfettario 2026?",
    "top_k": 10,
    "profile": "Commercialista",
    "materia": "IVA"
  }'
import requests, os

resp = requests.post(
    "https://bancadati.doczoom.ai/api/doczoom/answer",
    headers={"X-API-Key": os.environ["TAXHARVEST_API_KEY"]},
    json={
        "query": "Qual è la soglia forfettario 2025?",
        "top_k": 15,
    },
    timeout=120,
)
data = resp.json()
print(data["answer"])
const resp = await fetch("https://bancadati.doczoom.ai/api/doczoom/answer", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.TAXHARVEST_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    query: "Qual è la soglia forfettario 2025?",
    top_k: 15,
  }),
});
const data = await resp.json();
console.log(data.answer);

Response

{
  "query": "Qual è la soglia forfettario 2025?",
  "answer": "La soglia per il regime forfettario 2025 è di **85.000 €** di ricavi/compensi (Legge di Bilancio 2025, L. 207/2024). Il superamento oltre 100.000 € comporta uscita immediata dall'IVA forfettario.",
  "sources": [
    {
      "title": "INPS Circolare n. 27 del 30/01/2025",
      "url": "https://www.inps.it/...",
      "source": "inps_circolari",
      "doc_type": "circolare",
      "relevance_score": 0.92
    }
  ],
  "chunks": [/* 15 chunks completi con testo, citazione formale, autorità */],
  "confidence_level": "high",
  "top_score": 0.92,
  "needs_verification": false,
  "has_ai_summary": false,
  "timing_ms": {
    "embedding_ms": 200,
    "vector_search_ms": 800,
    "rerank_ms": 350,
    "llm_ms": 2500,
    "total_ms": 8500
  }
}

Response fields

FieldTypeDescription
answerstringRisposta sintetizzata dal LLM. 1–4 frasi tipicamente.
sourcesobject[]Fonti citabili (top 15). Per ogni fonte: title, url (fonte ufficiale), source, doc_type, relevance_score, doc_id, viewer_url (lettore interno /doc/{id} — usalo come target del bottone "Apri fonte").
chunksobject[]Chunks completi con testo, articolo, citazione formale.
confidence_levelstringhigh (top_score ≥0.7), medium (0.4–0.7), low (<0.4), no_results (0 chunk), cheatsheet_fastpath (v15).
top_scorefloatScore cross-encoder reranker del chunk top-1.
needs_verificationbooleanTrue se confidence < high. UI deve mostrare warning.
has_ai_summarybooleanTrue se almeno un chunk è AI-summary (mostrare disclaimer).
timing_msobjectBreakdown latenze per ogni stage (debug).
Latency expected Cache hit: ~100ms · Cache miss + retrieval normale: 6–15s · Query patologica con fast-path: 30–35s. Imposta timeout client a 120s per sicurezza.

Practice Areas (tassonomia) v25.86

Lista live di tutti i routings disponibili per /retrieve-legal. Use case: client carica all'avvio + cache, popola sub_area picker UI + classifier client-side.

GET /api/doczoom/practice-areas

Response

{
  "total_areas": 7,
  "total_routings": 42,
  "valid_slugs": ["amministrativo", "civile", "corporate", "lavoro", "penale", "privacy", "tributario"],

  "practice_areas": [
    {
      "practice_area": "civile",
      "sub_areas": ["mutuo", "fideiussione", "locazione_commerciale", null, ...],
      "routings": [
        {
          "sub_area": "mutuo",
          "slug": "civile__mutuo",
          "name": "Civile — Mutuo (artt. 1813-1822 c.c.)",
          "sources": ["normattiva", "cassazione"],
          "normattiva_codici": ["Codice Civile", "TUB - Testo Unico Bancario"],
          "cassazione_macro_aree": ["banca_finanza", "contratti_obbligazioni"],
          "must_include_defaults": ["Art. 1813 Codice Civile", "Art. 1815 Codice Civile", ...],
          "default_authority_mix": { "norms": 5, "case_law": 5, "practice": 0 }
        },
        /* ... altre routings ... */
      ]
    },
    /* ... altre 6 practice_areas ... */
  ]
}

Pattern d'uso — Client classifier

# 1. Bootstrap all'avvio (1 volta, cacheable)
PRACTICE_AREAS = requests.get(
    f"{TAXHARVEST_BASE}/api/doczoom/practice-areas",
    headers={"X-API-Key": KEY},
).json()
VALID_SLUGS = set(PRACTICE_AREAS["valid_slugs"])

# 2. Classifier rule-based client-side
CLASSIFIER_PATTERNS = [
    (r"\b(?:mutuo|TAEG|usura|tasso\s+soglia)\b", "civile", "mutuo"),
    (r"\b(?:fideiussor|fideiussione|art\s+1936|art\s+1957)\b", "civile", "fideiussione"),
    (r"\b(?:locazione|6\+6|L\.\s*392|equo\s+canone)\b", "civile", "locazione_commerciale"),
    (r"\b(?:patto\s+(?:di\s+)?non\s+concorrenza|art\s+2125)\b", "lavoro", "patto_non_concorrenza"),
    (r"\b(?:demansionamento|dequalifica|art\s+2103)\b", "lavoro", "mobbing_demansionamento"),
    (r"\b(?:DD|due\s+diligence|M&A|cessione\s+quote|SPA)\b", "corporate", "due_diligence"),
    (r"\b(?:GDPR|consenso|DPO|art\s+37\s+GDPR)\b", "privacy", "gdpr_compliance"),
    # ... 35+ pattern (vedi /practice-areas per lista completa)
]

def classify(query: str) -> tuple[str | None, str | None]:
    for pat, pa, sa in CLASSIFIER_PATTERNS:
        if re.search(pat, query, re.IGNORECASE):
            return pa, sa
    return None, None

# 3. Chiamata corretta a /retrieve-legal
pa, sa = classify(user_query)
resp = requests.post(
    f"{TAXHARVEST_BASE}/api/doczoom/retrieve-legal",
    headers={"X-API-Key": KEY},
    json={
        "query": user_query,
        "practice_area": pa,  # <-- CRITICO
        "sub_area": sa,        # <-- CRITICO
        "top_k": 12,
    },
).json()

Lista completa sub_areas (42 routings)

Practice areaSub_areaArticoli base / norme
civilecontrattiCodice Civile contratti
responsabilita_medicaArt. 1218, 2043, 2236 c.c.
responsabilita_extracontrattualeArt. 2043-2059 c.c.
compravendita_immobiliareArt. 1470, 1487, 1490, 1497, 2643, 2932 c.c.
locazione_commercialeL. 392/1978 art. 27-29, 31, 34, 35
locazione_abitativaL. 431/1998
condominioArt. 1117-1138 c.c.
fideiussioneArt. 1936-1957 c.c. (10 anchor)
mutuoArt. 1813-1822 c.c. + TUB
mandatoArt. 1703-1730 c.c.
comodatoArt. 1803-1812 c.c.
appaltoArt. 1655-1677 c.c.
assicurazioneArt. 1882-1932 c.c. + Cod. Ass. (D.Lgs. 209/2005)
donazioneArt. 769-809 c.c.
successioniArt. 587-712 c.c. + TU 346/1990
azione_revocatoriaArt. 2901-2904 c.c.
genericCodice Civile + CPC
lavoropatto_non_concorrenzaArt. 2125 c.c. + L. 300/70
licenziamentoArt. 18 Statuto + L. 604/1966 + Jobs Act
mobbing_demansionamentoArt. 2087, 2103, 2729 c.c.
trasferimento_aziendaArt. 2112, 2560 c.c.
genericLavoro generico
tributarioforfettarioTUIR + DPR 633/72
accertamentoDPR 600/1973 + Statuto Contribuente
contenziosoD.Lgs. 546/1992
ivaDPR 633/1972
genericTributario generico
penalereati_tributariD.Lgs. 74/2000
bancarottaRD 267/42 + Codice Crisi
responsabilita_231D.Lgs. 231/2001
genericCodice Penale + CPP
amministrativoappaltiD.Lgs. 36/2023 + CPA
urbanistica_ediliziaTU Edilizia (DPR 380/2001)
concorrenzaL. 287/90 + AGCM bollettini
genericCPA + L. 241/90
corporatecessione_quote_srlArt. 2469-2473 c.c.
operazioni_straordinarieArt. 2498-2506 c.c.
due_diligenceArt. 1337, 1370, 1489-1497 c.c. (excl. tributario)
genericCivile societario + TUF
privacygdpr_complianceGDPR art. 5, 6, 7, 13, 32, 35, 37, 83
data_breachGDPR art. 32, 33, 34
genericeur_lex + Garante + EDPB

DocZoom Retrieve BYOL · v25.75

Endpoint dedicato Bring Your Own LLM. Stessa engine di /query ma con default ottimizzati per consumo LLM downstream: top_k=15, min_relevance=0.4, context_format=llm_xml, group_by_document=true. Quello che serve a DocZoom per ricevere chunks pre-filtrati e generare la risposta col proprio LLM.

POST /api/doczoom/retrieve

Differenze rispetto a /query

Field/query default/retrieve defaultPerché
top_k815Più chunks → più contesto per il LLM
min_relevance0.00.4Filtra rumore prima del LLM (evita di sprecargli token su chunks irrilevanti)
context_formatcompactllm_xmlStruttura ottimale per Anthropic/OpenAI tool use
group_by_documentfalsetrueUnisce chunks consecutivi dello stesso doc → context più compatto

Example — call diretto

curl -X POST https://bancadati.doczoom.ai/api/doczoom/retrieve \
  -H "X-API-Key: $TAXHARVEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "patto di non concorrenza durata e corrispettivo",
    "sources": ["normattiva", "cassazione"]
  }'

Context output format = llm_xml (default)

Il campo context viene popolato in formato XML ottimizzato per Claude/GPT tool use:

<sources>
  <source id="1">
    <citation>Art. 2125 Codice Civile</citation>
    <title>Codice Civile — Art. 2125 Patto di non concorrenza</title>
    <url>https://www.normattiva.it/...</url>
    <type>normattiva/articolo_codice</type>
    <relevance>0.92</relevance>
    <text>Il patto con il quale si limita lo svolgimento dell'attività del prestatore di lavoro, per il tempo successivo alla cessazione del contratto, è nullo se non risulta da atto scritto, se non è pattuito un corrispettivo a favore del prestatore di lavoro e se il vincolo non è contenuto entro determinati limiti di oggetto, di tempo e di luogo. La durata del vincolo non può essere superiore a cinque anni, se si tratta di dirigenti, e a tre anni negli altri casi. [...]</text>
  </source>

  <source id="2">
    <citation>Cass. Civ. Sez. Lav. n. 17/2018</citation>
    <title>Cassazione — Requisiti validità patto non concorrenza</title>
    <url>https://www.italgiure.giustizia.it/...</url>
    <type>cassazione/sentenza</type>
    <relevance>0.85</relevance>
    <text>Il corrispettivo del patto di non concorrenza deve essere determinato o determinabile e non meramente simbolico. [...]</text>
  </source>
</sources>

Pattern Anthropic Claude — call diretto

# 1. Retrieve da TaxHarvest
chunks_resp = requests.post(
    "https://bancadati.doczoom.ai/api/doczoom/retrieve",
    headers={"X-API-Key": TAXHARVEST_KEY},
    json={"query": user_question},
).json()

# 2. Costruisci system prompt per Claude
system_msg = f"""Sei un assistente legale italiano. Rispondi citando SOLO le fonti seguenti.
Usa il formato [^N] dove N è l'id della source.

{chunks_resp['context']}

REGOLE:
- Cita ogni claim con riferimento esatto
- NON inventare numeri di sentenze o articoli non presenti
- Se le fonti non bastano, dillo esplicitamente"""

# 3. Chiama il TUO LLM (Anthropic Claude, OpenAI GPT, ...)
from anthropic import Anthropic
client = Anthropic()
answer = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=2048,
    system=system_msg,
    messages=[{"role": "user", "content": user_question}],
)

# 4. Componi response finale
return {
    "answer": answer.content[0].text,
    "sources": chunks_resp["sources"],
    "chunks_used": chunks_resp["chunks"],
    "confidence": chunks_resp["confidence_level"],
}

Risposta

Stesso schema di /query (DoczoomQueryResponse). Il valore di context varia in base a context_format.

DocZoom Query BYOL · low-level

Retrieve-only endpoint ottimizzato per Bring Your Own LLM: ricerca ibrida + reranking + filtering + ranking applicati, ma senza synthesis. Il client riceve chunks ben filtrati e li passa al proprio LLM per generare la risposta. Più veloce di /answer (~3–8s vs 15–25s).

Quando usare /query vs /answer
  • /answer — vuoi che TaxHarvest generi la risposta (chat semplice, mobile, integrazione plug-and-play). Pipeline 9-stage anti-allucinazione.
  • /query — hai il tuo LLM/applicazione (DocZoom Word plugin, orchestratore custom, RAG su dati propri da combinare). Ricevi chunks pre-filtrati e li componi col tuo LLM. Massima flessibilità.
POST /api/doczoom/query

Cosa è già applicato sui chunks ritornati

  • Hybrid search: vector HNSW + FTS italiano + entities + ontology
  • Cross-encoder reranker: top 50 candidati → top 15 con scoring multilingue
  • Junk filtering: rimossi chunks <80 char, firme digitali, numeri pagina, chunks con <30% caratteri alfabetici
  • Title-aware boost: query con riferimenti normativi (es. "L. 392/1978 art. 27") boostano i chunks con quel numero/anno nel titolo (anti fake-match)
  • Source hierarchy boost: Cass. SU > Cass. > Normattiva > AdE circolari
  • Vigenza penalty: atti abrogati downgradati (−0.10)
  • Dedup per URL + top-K cap
  • Confidence layer: high (top ≥ 0.7) / medium / low / no_results

Request body

FieldTypeRequiredDescription
querystringrequiredDomanda dell'utente.
top_kintegeroptionalDefault 8, range 1–30. Per BYOL consigliato 15–20.
sourcesstring[]optionalFiltro per fonte (es. ["normattiva", "ade_circolari"]).
collectionsstring[]optionalRaccolte tematiche L1 (es. ["diritto-civile"]) — alternativa a sources.
min_relevancefloatoptionalDefault 0.0. Filtra chunks sotto soglia.
use_hybridbooleanoptionalDefault true. Se false, solo vector search (più veloce ma meno preciso).
include_textbooleanoptionalDefault true. Se false, ritorna solo metadata (utile per UI "fonti suggerite").
context_formatstringoptionalv25.75+ Formato del campo context: "compact" (default, stringa pre-formatted plain), "llm_xml" (XML strutturato ottimo per Anthropic/OpenAI), "markdown" (footnote refs [^1]).
group_by_documentbooleanoptionalv25.75+ Default false. Se true, raggruppa chunks consecutivi dello stesso documento — riduce context size del ~40%.
countrystring[]optionalv25.89+ Filtro paese ISO-2 (default ["IT"] se omesso). Per chunks UAE (chunks_uae table, embedding Voyage-3-large 1024d) passare ["AE"] esplicitamente. Solo "IT" e "AE" supportati oggi; ogni altro valore → HTTP 400 unsupported_country. Il default IT non breaking change: tutti i client esistenti continuano a vedere solo corpus italiano.
modulesstring[]optionalv25.93+ Filtro per macro-area giuridica (es. ["diritto-civile"]). 10 moduli Lexroom-style: diritto-civile, diritto-tributario, diritto-penale, diritto-del-lavoro, diritto-amministrativo, diritto-societario, diritto-bancario, diritto-di-famiglia, privacy-data-protection, ip-proprieta-intellettuale. Restringe retrieval ai source + metadata del modulo. Compone in OR con sources/collections. Vedi GET /api/modules per dettagli. Module_id invalido → HTTP 400.
🇦🇪 UAE Corpus (v25.89, 18 mag 2026)

TaxHarvest ora indicizza fonti legali UAE in tabella separata chunks_uae con embedding Voyage-3-large 1024d (legal-domain, qualità superiore a text-embedding-3-small su inglese giuridico).

Corpus finale (v25.92): 836 docs / 28K chunks · 6 sources cablate: uae_cbuae (190 — Central Bank: AML/CFT, Federal Decree-Laws), uae_fta (343 — FTA VAT/CT/Excise Public Clarifications), uae_difc_legislation (144 — DIFC Arbitration / Companies / Contract / ecc.), uae_adgm_courts (80 — ADGM CFI judgments OCR Tesseract), uae_adgm_legislation (57 — ADGM Regulations + Abu Dhabi laws), uae_difc (22 — DIFC Courts judgments).

Test live retrieval: top scores 0.74-0.80 (high confidence) su query ADGM judgments / DIFC arbitration law / FTA VAT clarifications.

Bloccate: uae_elaws (TCP timeout Hetzner — serve Cloudflare Worker proxy .ae), uae_fsra (upstream text vuoto).

Pipeline: Voyage embed query (≈400ms) → HNSW search su chunks_uae → top-K. NO reranker, NO FTS italian, NO routing pratica IT (UAE è pipeline isolata). Tempo p50 ≈ 500ms (vs 3-9s pipeline IT).

Example — BYOL flow completo

curl -X POST https://bancadati.doczoom.ai/api/doczoom/query \
  -H "X-API-Key: $TAXHARVEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "ravvedimento operoso entro 90 giorni aliquota",
    "top_k": 15,
    "sources": ["normattiva", "ade_circolari"],
    "min_relevance": 0.4
  }'

Example — UAE corpus query (v25.89)

curl -X POST https://bancadati.doczoom.ai/api/doczoom/query \
  -H "X-API-Key: $TAXHARVEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "anti-money laundering CBUAE suspicious transactions reporting",
    "country": ["AE"],
    "top_k": 5
  }'

Response identica come schema (chunks + sources + confidence). Differenze: timing_ms.country = "AE", timing_ms.embedding_model = "voyage-3-large", chunk.source.source ∈ {"uae_cbuae", "uae_difc"}. Niente meta-handler / niente factuality judge / niente reranker (pipeline UAE isolata).

Response schema

{
  "query": "ravvedimento operoso entro 90 giorni aliquota",
  "total_results": 15,
  "confidence_level": "high",
  "top_score": 0.87,
  "needs_verification": false,
  "timing_ms": { "hybrid": 1200, "rerank": 340, "total": 1850 },

  "chunks": [
    {
      "text": "Art. 13 — Ravvedimento. 1. La sanzione è ridotta:\na) ad un decimo del minimo nei casi di mancato pagamento del tributo...",
      "source": {
        "title": "D.Lgs. 472/1997 — Art. 13 Ravvedimento",
        "url": "https://www.normattiva.it/atto/caricaDettaglioAtto?atto.dataPubblicazioneGazzetta=1997-12-19&atto.codiceRedazionale=097G0509&art.idArticolo=13",
        "source": "normattiva",
        "doc_type": "decreto_legislativo",
        "relevance_score": 0.87,
        "doc_id": 12345,
        "viewer_url": "https://bancadati.doczoom.ai/doc/12345"
      },
      "formal_citation": "Art. 13 D.Lgs. 472/1997",
      "article_path": "art_13",
      "authority": "Stato",
      "validity": "vigente",
      "document_date": "1997-12-18",
      "category": "legislazione",
      "is_ai_summary": false,
      "chunk_index": 0,
      "entities": [{"type": "norm", "value": "D.Lgs. 472/1997"}]
    },
    /* ... altri 14 chunks ordinati per relevance_score ... */
  ],

  "sources": [
    /* lista deduped delle source (chunks possono condividere stessa source) */
  ],

  "entities_found": [
    { "type": "norm", "value": "D.Lgs. 472/1997", "count": 8 },
    { "type": "percentage", "value": "0.083%", "count": 3 }
  ],

  "concepts_activated": [
    { "concept": "ravvedimento_operoso", "score": 0.92 }
  ],

  "context": "[NORMATTIVA | decreto_legislativo] D.Lgs. 472/1997 — Art. 13 Ravvedimento\nFonte: https://www.normattiva.it/...\nRilevanza: 87%\n---\nArt. 13 — Ravvedimento. 1. La sanzione...\n\n===\n\n[ADE_CIRCOLARI | circolare] Circolare 27/E 2013...\n..."
}

BYOL pattern — sintesi col tuo LLM

Una volta ottenuti i chunks pre-filtrati, costruisci il system prompt del tuo LLM con il campo context (già formattato). Esempio Python con qualsiasi provider:

# 1. Retrieve da TaxHarvest
resp = requests.post(
    "https://bancadati.doczoom.ai/api/doczoom/query",
    headers={"X-API-Key": API_KEY},
    json={
        "query": user_question,
        "top_k": 15,
        "min_relevance": 0.4,  # filtra chunks deboli
    },
).json()

if resp["confidence_level"] == "no_results":
    return resp["no_results_message"]  # "Non ho trovato fonti..."

# 2. Passa al tuo LLM con il context pre-formattato
system = f"""Sei un assistente legale. Rispondi SOLO usando le fonti seguenti.
Cita ogni claim con il riferimento normativo esatto.

FONTI (in ordine di rilevanza):
{resp['context']}"""

answer = your_llm.complete(system=system, user=user_question)

# 3. Componi response finale con citation tracking
return {
    "answer": answer.text,
    "sources": resp["sources"],
    "confidence": resp["confidence_level"],
    "chunks_used": resp["chunks"],
}

Decision matrix dettagliata

Caso d'usoEndpointNote
Plugin Word/Excel/PDF con documento allegato/queryCombina chunks con testo allegato nel tuo LLM
App mobile chat semplice/answerRisposta plug-and-play con anti-allucinazione end-to-end
Orchestratore agent multi-step/queryComponi step di reasoning con i chunks
UI con timeline ricerca/stage/streamSSE typed events per progress bar
Combinare con knowledge base proprietaria/queryMerge chunks TaxHarvest + chunks tuoi nel tuo LLM
Domanda con riferimento normativo specifico/articlesFetch deterministico per art. esatto (bypass semantic search)

DocZoom Stream (SSE)

Streaming Server-Sent Events della risposta LLM. Stessa logica di /answer ma con eventi tipizzati per timeline UI Onyx-like.

POST /api/doczoom/stream

Eventi SSE emessi

EventDataDescription
stage{id, state, label, ms}Stage del pipeline (retrieval, rerank, llm). State: start/done/skipped.
sources{sources, chunks, confidence_level}Sources e chunks dopo retrieval.
delta{text}Token incrementali del LLM (token-by-token).
meta{timing_ms, llm_provider}Metadati finali.
done{finish_reason, truncated}v25.8: finish_reason"stop" | "length" | "content_filter" | "error" (OpenAI-compatible). truncated: true sse finish_reason == "length" (max_output_tokens raggiunto).
error{message}Errore.

Request body

Accetta lo stesso schema di /answer (vedi sezione DocZoom Answer). Tutti i field sotto sono supportati anche su /stream.

FieldTypeDescription
querystringDomanda dell'utente.
top_kintegerNumero chunks retrieval (default 10, range 1-25). Stesso schema di /answer.
sourcesarray<string>Filtro fonti (es. ["normattiva","cassazione"]).
collectionsarray<string>Slug collections L1 (es. ["diritto-civile","privacy-data-protection"]).
document_contextstringv25.2+ Testo opzionale di un documento allegato dall'utente (contratto, parere, circolare aziendale). Il LLM lo analizza usando la banca dati come authority retrieval. Max 100.000 caratteri (~25K token, sotto il context window del modello attivo). NON comprimere il documento dentro query: passa il testo intero qui e tieni query per la domanda del consulente ("è valido?", "rischi?", "compliance GDPR?").
document_namestringNome file dell'allegato (es. "contratto_locazione.pdf"). Usato come label nel system prompt per dare contesto al LLM. Max 200 caratteri.
profilestringProfilo professionale utente (es. "Avvocato Tributarista", "Notaio"). Attiva controlli verticali sul LLM judge.
materiastringMateria (es. "IVA", "Lavoro", "Successioni").
prefer_speedbooleanSe true, salta re-prompt automatico in caso di ISSUE judge. Latency −15-25s; trade-off qualità. Default false.
max_output_tokensintegerv25.70+ Override max token output LLM. Range 100-8192, default 4096. Per Q&A breve usa 1000; per analisi documento intero usa 4096; per redaction multi-clausola fino a 8192.

Use case: Legal Chat con documento allegato

Il client (Plugin DocZoom Word / Legal Chat) ha l'utente che carica un contratto, una circolare aziendale, un parere — qualunque PDF/DOCX che deve essere analizzato contro la banca dati normativa. Pattern corretto: estrai il testo del documento lato client e passalo come document_context, NON comprimerlo dentro la query. La banca dati TaxHarvest viene usata come source/authority retrieval, il LLM ragiona sul documento allegato con il diritto italiano come riferimento.

POST /api/doczoom/stream
{
  "query": "Questa clausola di non concorrenza è valida secondo il diritto italiano?",
  "document_context": "ART. 7 — PATTO DI NON CONCORRENZA\nIl Lavoratore si impegna, per la durata di 36 mesi dalla cessazione del rapporto di lavoro, a non svolgere attività concorrenziale presso aziende del settore alimentare in tutto il territorio della Repubblica Italiana. A titolo di corrispettivo, il Lavoratore percepirà la somma di € 5.000 una tantum alla cessazione del rapporto.\n\n[... resto del contratto ...]",
  "document_name": "contratto_lavoro_mario_rossi.pdf",
  "max_output_tokens": 2048,
  "profile": "Avvocato Civilista",
  "materia": "Lavoro"
}

Il LLM riceverà nel system prompt: "L'utente ha allegato il documento 'contratto_lavoro_mario_rossi.pdf'..." e nel context il testo del contratto + i 10 chunks più rilevanti dalla banca dati (art. 2125 c.c., Cass. 17/2018 sui requisiti, ecc.).

Example (browser, streaming consumption)

const resp = await fetch("/api/doczoom/stream", {
  method: "POST",
  headers: {"X-API-Key": KEY, "Content-Type": "application/json"},
  body: JSON.stringify({
    query: "È valido il patto di non concorrenza?",
    document_context: contractText,  // estratto lato client da .pdf/.docx
    document_name: "contratto.pdf",
    max_output_tokens: 2048,
  }),
});
const reader = resp.body.getReader();
const decoder = new TextDecoder();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  // Parse SSE: event: delta\ndata: {"text": "L'art..."}
  const chunk = decoder.decode(value);
  console.log(chunk);
}

DocZoom Reference

Lookup di un riferimento normativo specifico (es. "art. 13 DPR 633/72"). Più preciso di /answer per citazioni dirette.

POST /api/doczoom/reference

Request body

FieldTypeDescription
referencestringCitazione libera. v25.28+ riconosce articolo specifico + codici brevi (c.c., c.p., c.p.c., c.p.p., TUIR, TUF, TUB, ecc.).
articlestringNumero articolo opzionale (es. "27", "2112-bis"). Estratto da reference se presente.
codicestringCodice opzionale (mappato da abbrev → nome canonico).

Example

curl -X POST https://bancadati.doczoom.ai/api/doczoom/reference \
  -H "X-API-Key: $KEY" \
  -d '{"reference": "L. 392/1978 art. 27"}'
# → "Equo Canone (L. 392/1978) - Art. 27" (1 risultato esatto)

curl -X POST https://bancadati.doczoom.ai/api/doczoom/reference \
  -H "X-API-Key: $KEY" \
  -d '{"reference": "art. 1384 c.c."}'
# → "Codice Civile - Art. 1384 - Riduzione della penale"

DocZoom Articles v25.30

Fetch deterministico di articoli specifici per una legge o un codice. Bypassa completamente il semantic search — ideale per audit di conformità su tipo di contratto noto, dove il client predefinisce una whitelist di articoli imperativi e li fetcha sempre.

POST /api/doczoom/articles

Request body

FieldTypeRequiredDescription
lawstringopzionale*Legge speciale (es. "L. 392/1978", "DPR 633/1972", "D.Lgs. 81/2008").
codicestringopzionale*Codice (es. "c.c.", "Codice Civile", "TUIR", "TUF").
articles(string|int)[]requiredLista numeri articoli da fetchare (es. [27, 32, 34] o ["1384", "2112-bis"]). Min 1, max 50.
include_textbooleanopzionaleDefault true. Se false ritorna solo metadata (no testo articolo).

* Almeno uno tra law e codice richiesto.

Response

{
  "law": "L. 392/1978",
  "codice": null,
  "articles_requested": ["27", "32", "34", "36"],
  "found_count": 4,
  "missing_count": 0,
  "articles": [
    {
      "article": "27",
      "found": true,
      "title": "Equo Canone (L. 392/1978) - Art. 27",
      "url": "https://www.brocardi.it/legge-equo-canone/...",
      "source": "normattiva",
      "doc_type": "legge",
      "citation": "art. 27 L. 392/1978",
      "text": "La durata delle locazioni e sublocazioni di immobili urbani non può essere inferiore a sei anni..."
    },
    // ... altri articoli
  ]
}

Examples

# Locazione commerciale: 4 articoli imperativi della L. 392/1978
curl -X POST https://bancadati.doczoom.ai/api/doczoom/articles \
  -H "X-API-Key: $KEY" \
  -d '{"law": "L. 392/1978", "articles": [27, 32, 34, 36]}'

# Codice Civile: clausola penale + illecito + trasferimento azienda
curl -X POST https://bancadati.doczoom.ai/api/doczoom/articles \
  -H "X-API-Key: $KEY" \
  -d '{"codice": "c.c.", "articles": [1384, 2043, 2112]}'

# TUIR articoli (no testo, solo metadata)
curl -X POST https://bancadati.doczoom.ai/api/doczoom/articles \
  -H "X-API-Key: $KEY" \
  -d '{"codice": "TUIR", "articles": [54, 85], "include_text": false}'

Use case principale

Plugin DocZoom Word — audit di conformità contratti. Il Compliance Query Planner predefinisce una whitelist di articoli imperativi per ogni ContractType (es. locazione commerciale = L. 392/1978 art. 27/32/34/36 + art. 1384 c.c.) e fetcha sempre questi via /articles. Risolve il limit di /query sul ranking semantico delle leggi speciali.

Special norm aliases (v25.37)

Norme orizzontali NON ancora indicizzate art-by-art (es. GDPR Reg. UE 2016/679) ritornano una response strutturata invece di matchare per substring fuzzy. Esempio:

curl -X POST https://bancadati.doczoom.ai/api/doczoom/articles \
  -H "X-API-Key: $KEY" \
  -d '{"law": "GDPR", "articles": [6, 7]}'

# Response (no FP su Codice Protezione Civile):
{
  "law": "Reg. UE 2016/679",
  "found_count": 0,
  "missing_count": 2,
  "articles": [
    {"article": "6", "found": false, "_not_indexed": true,
     "_message": "Il Regolamento UE 2016/679 (GDPR) non è ancora indicizzato..."}
  ],
  "_warning": "...usare Codice Privacy nazionale come proxy."
}

Aliases attualmente configurati: GDPR, Reg. UE 2016/679, Regolamento Generale Protezione Dati. Più verranno aggiunti man mano che si trovano gap di indicizzazione.

Garanzie

  • Deterministico: stessa request → stesso output. No semantic ranking variability.
  • Articoli mancanti ritornano {found: false} invece di errore HTTP — il client può aggregare lo stato.
  • Performance: ~50-200ms per request (1 SQL query/articolo).
  • Costo: $0 (no LLM, no embedding).

Compliance Contract Types v25.32

Lista dei tipi di contratto curati per il flow audit conformità. Sostituisce hardcoding lato plugin.

GET /api/compliance/contracts

Response

{
  "count": 7,
  "contracts": [
    {"type": "locazione-commerciale", "label": "Locazione commerciale (uso non abitativo)", "description": "..."},
    {"type": "locazione-abitativa", "label": "Locazione abitativa", "description": "..."},
    {"type": "lavoro-subordinato", "label": "Contratto di lavoro subordinato", "description": "..."},
    {"type": "patto-non-concorrenza", "label": "Patto di non concorrenza", "description": "..."},
    {"type": "nda-riservatezza", "label": "Accordo di riservatezza (NDA)", "description": "..."},
    {"type": "compravendita-immobile", "label": "Compravendita immobiliare", "description": "..."},
    {"type": "appalto-privato", "label": "Contratto di appalto privato", "description": "..."}
  ]
}

Example

curl https://bancadati.doczoom.ai/api/compliance/contracts \
  -H "X-API-Key: $KEY"

Compliance Contract Detail v25.32 + v25.37

Whitelist imperative_norms (specifiche del tipo contratto) + tipiche_violazioni (checklist) + horizontal_norms (norme cross-cutting che si applicano sempre — GDPR, Codice Consumo, ecc.). Pensato per il flow Conformità del plugin DocZoom Word: il client lo chiama dopo che l'utente ha selezionato il tipo contratto, e ottiene tutti i riferimenti legali da prependere al normativeContext.

GET /api/compliance/contracts/{contract_type}

Path params

FieldDescription
contract_typeChiave del tipo contratto (es. locazione-commerciale). Vedi /api/compliance/contracts per la lista.

Query params

FieldTypeDefaultDescription
fetch_textbooleanfalseSe true, fetcha il testo completo degli articoli imperativi (chiamata interna a /articles con cache 24h). Latency ~200-500ms.

Response

{
  "type": "locazione-commerciale",
  "label": "Locazione commerciale (uso non abitativo)",
  "description": "Contratto di locazione di immobile urbano adibito ad uso diverso...",
  "imperative_norms": [
    {"law": "L. 392/1978", "articles": [27, 32, 34, 36, 37, 38, 39, 40, 41, 42],
     "tema": "Disciplina locazioni uso diverso: durata, ISTAT, indennità avviamento..."},
    {"codice": "c.c.", "articles": [1384, 1385, 1571, 1573, 1575],
     "tema": "Clausola penale, caparra, nozione locazione, obblighi locatore"}
  ],
  "tipiche_violazioni": [
    "Durata < 6 anni (L. 392 art. 27)",
    "Aggiornamento ISTAT > 75% indice (L. 392 art. 32)",
    "Limitazione/condizionamento del diritto di recesso del conduttore per gravi motivi (L. 392 art. 27 c. 8 — il diritto è inderogabile)",
    "Mancanza informativa privacy / trattamento dati conduttore (GDPR / D.Lgs. 196/2003)",
    ...
  ],
  "horizontal_norms": [   // v25.37 — norme cross-cutting che si applicano a questo tipo
    {
      "key": "gdpr",
      "label": "Privacy / Trattamento dati personali (GDPR)",
      "law": "Reg. UE 2016/679",
      "fallback_codice": "Codice della Privacy",
      "articles": [6, 7, 13, 14, 15, 17, 22, 28, 32, 35, 44],
      "tema": "Basi legali, consenso, informativa, diritti interessato...",
      "indicizzato": false,
      "fallback_indicizzato": true,
      "warning": "GDPR non indicizzato art-by-art; usare Codice Privacy come proxy"
    }
  ],
  "articles": [...]  // se fetch_text=true: imperative + horizontal aggregati con field `category` (imperative|horizontal)
}

Examples

# Lista whitelist (lightweight, no testo articoli)
curl https://bancadati.doczoom.ai/api/compliance/contracts/locazione-commerciale \
  -H "X-API-Key: $KEY"

# Con full articles (testo completo)
curl "https://bancadati.doczoom.ai/api/compliance/contracts/locazione-commerciale?fetch_text=true" \
  -H "X-API-Key: $KEY"

DocZoom Tool

Strumenti real-time (VIES check, ricerca articoli, ecc.). Vedi /api/doczoom/capabilities per la lista completa.

POST /api/doczoom/tool

Request body

FieldTypeDescription
toolstringNome tool (vies_check, article_lookup, etc.).
paramsobjectParametri specifici del tool.

DocZoom Capabilities

GET /api/doczoom/capabilities

Lista delle capabilities/tools disponibili.

Chat

Chat con context multi-turn. Mantiene history per follow-up domande.

POST /api/chat

Request

FieldTypeDescription
messagestringMessaggio utente (max 10000 char).
historyobject[]Storia conversazione (lista {role, content}).

Sources

GET /api/sources

Lista delle 61 fonti IT dati disponibili (+ 6 UAE), scrapate automaticamente da scheduler interno. Backend di acquisizione: 3-tier (HTTP proxy interno, Browser rendering, direct fetch).

Inventario completo (counts 13 mag 2026)

Giurisprudenza (610K+ documenti)

SourceDocsDescrizioneBackend
cassazione335.188Sentenze civili + penali + costituzionali Corte di Cassazione (1996-oggi)Solr ItalGiure (direct + cortedicassazione.it)
giustizia_amministrativa267.795TAR 30 sedi + Consiglio di Stato + CGA Sicilia (2020-oggi, backfill in corso)Playwright Liferay portlet form
corte_costituzionale3.808Sentenze + ordinanze Corte CostituzionalePlaywright cortecostituzionale.it
curia_cgue1.410Comunicati stampa CGUE Curia Lussemburgo (IT)proxy interno curia.europa.eu
giustizia_tributaria_massimario1.069Massime tributarie CassazioneScraping ufficio massimario
hudoc_cedu9Sentenze landmark CEDU v. Italia (Cestaro, Torreggiani, Provenzano, ecc.)HUDOC PDF endpoint
corte_dei_conti1SPA banchedati.corteconti.it (limitato, richiede session dedicata)
giustizia_tributaria3Limitato (Akamai+QueueIT block)

Normativa italiana (15K+ articoli)

SourceDocsDescrizione
normattiva14.96365 codici art-by-art: CC, CP, CPC, CPP, Costituzione, TUIR, TUB, TUF, Cod. Crisi Impresa, Cod. Privacy, Nuovo Cod. Appalti, Statuto Lavoratori, Negoziazione Assistita, ecc.
gazzetta_ufficiale2.837Atti GU serie generale (RSS daily + backfill)

Normativa UE (1.8K+ documenti)

SourceDocsDescrizione
eur_lex1.74738 atti UE art-by-art: GDPR, AI Act, NIS 1+2, DORA, DSA, DMA, MiCAR, PSD2, MAR, eIDAS 1+2, Data Act, DGA, CRA, CER, ENISA, ePrivacy, AMLD 4-6, Reg. AML 2024, ATAD, DAC 1+7, Mifid II, Direttiva OPA, Reg. Prospetto, Direttiva Trasparenza, Whistleblowing + 15 decisioni adeguatezza GDPR
eurlex76Dataset EUR-Lex legacy (pre-v25.43)

Prassi fiscale (7.4K+ documenti AdE)

SourceDocsDescrizione
ade_interpelli3.237Risposte interpello AdE
ade_risoluzioni2.972Risoluzioni AdE (2006-oggi)
ade_circolari781Circolari AdE interpretative
ade_provvedimenti139Provvedimenti del Direttore AdE
ade_guide104Guide pratiche AdE (Forfettario, Cedolare, Superbonus, ecc.)
ade_modelli11Modelli dichiarativi + istruzioni
agenzia_entrate_news28News + comunicati stampa AdE
mef_convenzioni_doppia_imposizione73Convenzioni internazionali bilaterali contro doppie imposizioni
mef_finanze25Comunicati MEF
agenzia_dogane2Circolari ADM dogane/accise

Previdenza & Lavoro (8.2K+ documenti)

SourceDocsDescrizione
cnel_ccnl6.762Contratti Collettivi Nazionali (CCNL settoriali archivio CNEL)
inps_messaggi821Messaggi INPS operativi
inps_circolari595Circolari INPS
ministero_lavoro5Min. Lavoro atti/circolari
ispettorato_lavoro1INL note ispezioni

Authority indipendenti IT (1.9K+ documenti)

SourceDocsDescrizione
agcm_bollettini808Bollettini settimanali AGCM antitrust (2010-2026 backfill, intese/concentrazioni/abusi)
agcom537Delibere AGCOM autorità comunicazioni
abf280Decisioni ABF Arbitro Bancario Finanziario
uif87UIF Banca d'Italia — Quaderni antiriciclaggio + Avvisi
agid80AgID — Linee guida PA digitale + notizie + circolari
anac67ANAC — atti, comunicati, notizie autorità anticorruzione
adm45ADM — Circolari, determinazioni, risoluzioni dogane (Liferay PDF)
banca_italia35Disposizioni vigilanza Banca d'Italia + BCE rates daily
ivass33IVASS — Regolamenti + bollettini vigilanza assicurazioni
arera9ARERA — Delibere autorità energia, reti, ambiente
consob4News Consob (SPA limitato)

Ministeri & Enti pubblici IT (270+ documenti)

SourceDocsDescrizione
mlps77Ministero del Lavoro — Notizie + comunicati istituzionali
inail65INAIL — Pubblicazioni + scadenze + avvisi
ministero_lavoro5Min. Lavoro atti/circolari (legacy)
ispettorato_lavoro1INL note ispezioni

Authority UE (440+ documenti)

SourceDocsDescrizione
eba200EBA — Guidelines + RTS + ITS + Opinions banking (PDF diretti)
eiopa92EIOPA — Publications + Solvency II rulebook insurance/pensions
esma87ESMA — Press releases + publications + databases securities markets
amla21AMLA — Anti-Money Laundering Authority (agenzia UE 2024)

Standard-setter internazionali (65+ documenti)

SourceDocsDescrizione
iasb42IASB — IFRS / IAS Standards internazionali (testi master)
fsb16FSB — Financial Stability Board publications globali
bis_bcbs7BIS BCBS — Basel Committee banking standards

Privacy & GDPR (440+ documenti)

SourceDocsDescrizione
wp29226WP29 Article 29 Working Party archive (legacy pre-EDPB)
edpb115EDPB European Data Protection Board (linee guida + opinion)
garante_privacy62Provvedimenti Garante Privacy IT

Internazionale & specialistiche (270+ documenti)

SourceDocsDescrizione
borsa_italiana263Regolamenti + avvisi storici Borsa Italiana (16 sezioni)
cnf_deontologico75Codice Deontologico Forense (CNF 2014)
un_treaties51Convenzione ONU Diritti del Fanciullo (51 art.)
oic_principi_contabili48Principi contabili nazionali OIC 8-32
oic42OIC legacy (eventi/categorie homepage)
uibm41Circolari + decreti UIBM proprietà industriale
fnc_commercialisti25FNC Fondazione Nazionale Commercialisti documenti
hcch_treaties2Convenzioni Aja 1980 + 1996 (sottrazione/protezione minori)
istat2ISTAT comunicati rilevanti
epo_boards_appeal1EPO Boards of Appeal Case Law 2025 (1988 pp, 3259 chunks full text)
wipo_treaties1TRIPS Agreement (WTO 1994)
council_europe1CEDU testo italiano (Convenzione Europea Diritti dell'Uomo)

Response example

{
  "sources": [
    {"name": "cassazione", "count": 335188},
    {"name": "giustizia_amministrativa", "count": 267795},
    {"name": "normattiva", "count": 14963},
    {"name": "cnel_ccnl", "count": 6762},
    /* ... totale 61 fonti IT (+ 6 UAE), vedi tabella sopra */
  ]
}

Modules (macro-area + profilo) v25.93+25.103 · LEXROOM-STYLE

18 moduli totali: 10 IT macro-area giuridica (Civile, Tributario, Penale, ecc.) + 3 IT per profilo professionale (v25.103: commercialista, tributarista, consulente-lavoro) + 5 UAE. Permettono a DocZoom di filtrare il retrieval senza enumerare manualmente le 67 sources. Per profili più granulari (es. commercialista-iva) usa le 66 collections L1-L3.

GET /api/modules

Lista i 18 moduli disponibili con id, name, icon, description, filter_count e sources coperte.

Response schema

{
  "modules": [
    {
      "id": "diritto-civile",
      "name": "Diritto Civile",
      "icon": "⚖️",
      "short": "Civile",
      "description": "Codice Civile, CPC, Cassazione civile...",
      "filter_count": 6,
      "sources": ["cassazione", "corte_costituzionale", ...]
    },
    /* ... 10 moduli totali */
  ],
  "count": 18,
  "usage_hint": "Passa modules=['diritto-civile'] o ['commercialista'] a POST /api/doczoom/query"
}

Query params

FieldTypeRequiredDescription
countrystringoptionalv25.94+ Filtro paese ISO-2: IT | AE | all (default all). Es. ?country=AE → solo i 5 moduli UAE.

🇮🇹 Moduli IT per materia giuridica (10, Lexroom-style)

IDNomeMacro-area
diritto-civileDiritto CivileCC, CPC, Cass. civile, Cod. Consumo, Crisi Impresa, CGUE, CNF
diritto-tributarioDiritto TributarioTUIR, IVA, Statuto Contribuente, AdE, Cass. tributario, CGUE
diritto-penaleDiritto PenaleCP, CPP, D.Lgs. 74/2000, Cass. penale
diritto-del-lavoroDiritto del LavoroStatuto Lavoratori, INPS, INAIL, CCNL, Cass. lavoro
diritto-amministrativoDiritto AmministrativoCod. Appalti, TAR, CdS, AGCM, AGCOM, ANAC, Corte dei Conti
diritto-societarioDiritto SocietarioCC libro V, TUF, Consob, ESMA, Borsa IT, OIC
diritto-bancarioDiritto Bancario e FinanziarioTUB, TUF, ABF, Banca d'Italia, EBA, BCBS
diritto-di-famigliaDiritto di FamigliaCC famiglia, CEDU, Convenzione Aja, Cass. famiglia
privacy-data-protectionPrivacy e Data ProtectionGDPR, Cod. Privacy, Garante, EDPB, WP29, CEDU privacy
ip-proprieta-intellettualeIP — Proprietà IntellettualeCod. PI, WIPO, EPO, UIBM, CGUE IP

👔 Moduli IT per profilo professionale (3, v25.103)

Macro-moduli che aggregano fonti di più materie secondo le esigenze tipiche del professionista. Per granularità maggiore (sub-tematiche L2/L3) vedi le 66 collections.

IDNomeCoverage
commercialistaCommercialistaFiscale (IVA+IRPEF+IRES+IRAP+dichiarazioni) + bilancio (OIC/IFRS) + societario + crisi impresa + lavoro consulenza. 27 filters, 5 macro_area cassazione.
tributaristaAvvocato TributaristaContenzioso tributario (CTP/CTR + Cass. trib.) + penale tributario (D.Lgs. 74/2000) + procedure deflattive + riscossione. Più focused su contenzioso vs commercialista.
consulente-lavoroConsulente del LavoroContratti (a termine, apprendistato, somministrazione, smart working) + licenziamenti + CCNL + sicurezza (D.Lgs. 81/2008) + INPS/INAIL + immigrazione.

🇦🇪 Moduli UAE disponibili (country=AE)

IDNomeCoverage
uae-taxUAE TaxFTA Public Clarifications: VAT 5%, Corporate Tax 9%, Excise (343 docs)
uae-banking-amlcftUAE Banking & AML/CFTCentral Bank UAE: AML/CFT, Federal Decree-Laws, licensing financial institutions (190 docs)
uae-difcUAE — DIFC (Dubai)DIFC Courts judgments + DIFC Laws (Arbitration, Companies, Contract, ecc.) — 166 docs
uae-adgmUAE — ADGM (Abu Dhabi)ADGM Courts CFI judgments (OCR) + ADGM Regulations — 137 docs
uae-common-lawUAE Common Law (DIFC + ADGM)Cross-cut sui 2 financial centres common-law UAE (303 docs)

⚠️ Cross-country validation: i moduli UAE richiedono country=["AE"]; i moduli IT richiedono country=["IT"] (o default). Mismatch → HTTP 400 module_country_mismatch.

Esempio cURL

curl https://bancadati.doczoom.ai/api/modules \
  -H "X-API-Key: $TAXHARVEST_API_KEY"

Module Detail (live counts)

GET /api/modules/{module_id}

Dettaglio di un singolo modulo + count documenti per source (live).

Path params

FieldTypeDescription
module_idstringID modulo (es. diritto-tributario). Vedi GET /api/modules per la lista.

Response schema

{
  "id": "diritto-tributario",
  "name": "Diritto Tributario",
  "icon": "💶",
  "short": "Tributario",
  "description": "Normativa tributaria nazionale + UE...",
  "filters": [
    {"source": "cassazione", "metadata": {"macro_area": ["tributario"]}},
    {"source": "normattiva", "metadata": {"codice": ["TUIR..."]}},
    /* ... 17 filtri totali */
  ],
  "sources": ["cassazione", "ade_circolari", "ade_interpelli", ...],
  "doc_counts": {
    "cassazione": 71101,
    "corte_costituzionale": 3808,
    "ade_interpelli": 3237,
    /* ... per ogni source */
  },
  "total_docs": 85304
}

Usage in retrieval

Passa modules in POST /api/doczoom/query per filtrare i chunks ai soli source/metadata del modulo:

curl -X POST https://bancadati.doczoom.ai/api/doczoom/query \
  -H "X-API-Key: $TAXHARVEST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "ravvedimento operoso entro 90 giorni",
    "modules": ["diritto-tributario"],
    "top_k": 10
  }'

Note: i moduli compongono in OR con sources e collections (più permissive). Un module_id non valido → HTTP 400 unknown_module. Quando country=["AE"], i moduli vengono ignorati (UAE pipeline isolata).

Source Categories

GET /api/source/{source_name}/categories

Macro-categorie per una fonte specifica (es. Normattiva → CC, CP, TUIR, ...).

Response (v25.8+)

Per normattiva, ogni categoria contiene un slug stable usabile come parametro filtro:

{
  "source": "normattiva",
  "categories": [
    {"name": "Codice Civile", "slug": "cc", "count": 3029},
    {"name": "TUIR - Testo Unico Imposte sui Redditi", "slug": "tuir", "count": 236},
    /* ... vedi tabella 65 codici sotto */
  ]
}

65 codici Normattiva disponibili (count 13 mag 2026)

Codici fondamentali

SlugNomeArticoli
ccCodice Civile3.029
cpcCodice di Procedura Civile1.139
cpCodice Penale864
cppCodice di Procedura Penale803
costCostituzione140
preleggiPreleggi (Disposizioni sulla Legge in Generale)31
disp_att_ccDisposizioni Attuazione Codice Civile312
disp_att_cppDisposizioni di attuazione Cod. Proc. Penale323
cpp_minoriCodice di Procedura Penale Minorile (DPR 448/1988)47

Tributario

SlugNomeArticoli
tuirTUIR - Testo Unico Imposte sui Redditi236
ivaDecreto IVA (DPR 633/1972)171
dpr600Accertamento Imposte sui Redditi (DPR 600/1973)107
turTesto Unico Imposta di Registro (DPR 131/1986)83
statuto_contribuenteStatuto del Contribuente (L. 212/2000)37
reati_tributariLegge sui Reati Tributari (D.Lgs. 74/2000)34
cptCodice del Processo Tributario (D.Lgs. 546/1992)94
tusdTesto Unico Successioni e Donazioni (D.Lgs. 346/1990)66
irapRiordino Finanza Enti Territoriali / IRAP (D.Lgs. 446/1997)50

Bancario, finanziario, assicurazioni

SlugNomeArticoli
tufTUF - Testo Unico Intermediazione Finanziaria514
tubTUB - Testo Unico Bancario363
capCodice delle Assicurazioni Private (D.Lgs. 209/2005)611

Lavoro

SlugNomeArticoli
tuslTesto Unico Sicurezza Lavoro (D.Lgs. 81/2008)321
jobs_actJobs Act - Disciplina Organica Contratti (D.Lgs. 81/2015)66
statuto_lavoratoriStatuto dei Lavoratori (L. 300/1970)41
tupiTesto Unico Pubblico Impiego (D.Lgs. 165/2001)104
pari_oppCodice delle Pari Opportunità (D.Lgs. 198/2006)72
l104Legge 104 - Disabilità (L. 104/1992)48

Amministrativo, appalti, edilizia

SlugNomeArticoli
cpaCodice del Processo Amministrativo139
appaltiNuovo Codice Appalti (D.Lgs. 36/2023)233
appalti_vecchioCodice dei Contratti Pubblici (legacy)222
tueTesto Unico Edilizia151
tuelTesto Unico Enti Locali (D.Lgs. 267/2000)291
espropriazioniTesto Unico Espropriazioni (DPR 327/2001)70
cgccCodice di Giustizia Contabile (D.Lgs. 174/2016)221
l241Legge sul Procedimento Amministrativo (L. 241/1990)51
cadCodice dell'Amministrazione Digitale (D.Lgs. 82/2005)123
antimafiaCodice Antimafia (D.Lgs. 159/2011)136
protezione_civileCodice della Protezione Civile (D.Lgs. 1/2018)51

Penale specialistico

SlugNomeArticoli
ord_penOrdinamento Penitenziario (L. 354/1975)137
stupefacentiTesto Unico Stupefacenti (DPR 309/1990)142

Civile specialistico

SlugNomeArticoli
codice_consumoCodice del Consumo (D.Lgs. 206/2005)241
privacyCodice della Privacy221
ambienteCodice dell'Ambiente (D.Lgs. 152/2006)443
cpiCodice della Proprietà Industriale (D.Lgs. 30/2005)291
beni_culturaliCodice dei Beni Culturali e del Paesaggio (D.Lgs. 42/2004)192
stradaCodice della Strada (D.Lgs. 285/1992)266
cceCodice delle Comunicazioni Elettroniche (D.Lgs. 259/2003)267
terzo_settoreCodice del Terzo Settore (D.Lgs. 117/2017)105
cdtCodice del Turismo (D.Lgs. 79/2011)77
cdndCodice della Nautica da Diporto (D.Lgs. 171/2005)94
mediazioneMediazione Civile e Commerciale (D.Lgs. 28/2010)44
negoziazione_assistitaNegoziazione Assistita (DL 132/2014 conv. L. 162/2014)37

Crisi d'impresa, immobiliare, famiglia, immigrazione

SlugNomeArticoli
cciiCodice della Crisi d'Impresa e dell'Insolvenza411
lfLegge Fallimentare (RD 267/1942)301
locazioniDisciplina Locazioni Abitative (L. 431/1998)16
equo_canoneEquo Canone (L. 392/1978)85
ldivLegge sul Divorzio (L. 898/1970)16
immigrazioneTesto Unico Immigrazione (D.Lgs. 286/1998)77

Altro

SlugNomeArticoli
altriAtti normativi vari (non codificati)

I client possono usare sia lo slug (es. cc) sia il nome canonico (es. "Codice Civile") come parametro category. La response include resolved_category per breadcrumb UI.

Source Documents

GET /api/source/{source_name}/documents

Query params

ParamTypeDescription
categorystringFiltro categoria. Per normattiva, accetta slug (es. cc, tuir) oppure nome canonico (es. "Codice Civile") — alias trasparente. Slug altri raggruppa atti non codificati.
limitintegerDefault 50, max 200.
offsetintegerPaginazione.

Response field (v25.8)

resolved_category espone il nome canonico matchato (utile per breadcrumb UI quando il client passa uno slug).

Examples

# Slug stable
curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/source/normattiva/documents?category=cc&limit=10"

# Equivalente con nome esteso
curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/source/normattiva/documents?category=Codice%20Civile"

# Atti non codificati (decreto_legislativo, legge, dpr, decreto_legge, ...)
curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/source/normattiva/documents?category=altri"

Document Full (con testo)

Nuovo in v25.8.2: ritorna metadati documento + chunks + full_text. Usato dal frontend DocZoom (Codici Navigator) per renderizzare il testo dell'articolo cliccato. /source/.../documents ritorna solo metadata; questo endpoint fornisce il testo completo.

GET /api/document/{id}

Path params

ParamTypeDescription
idintegerDocument ID (es. ottenuto da /source/normattiva/documents).

Response

{
  "id": 211124,
  "source": "normattiva",
  "doc_type": "altro",
  "title": "Codice di Procedura Penale - Art. 1 - Giurisdizione penale",
  "url": "https://it.wikisource.org/wiki/Codice_di_procedura_penale#Art._1",
  "unique_id": "normattiva::https://it.wikisource.org/...",
  "published_date": "1988-09-22",
  "metadata": {"codice": "Codice di Procedura Penale", "articolo": "1", /* ... */},
  "chunks": [
    {
      "id": 1715309,
      "chunk_index": 0,
      "total_chunks": 1,
      "text": "1. La giurisdizione penale è esercitata dai giudici previsti...",
      "metadata": {"source_summary": "wikisource_verbatim"}
    }
  ],
  "chunks_count": 1,
  "full_text": "1. La giurisdizione penale è esercitata dai giudici..."
}

Examples

# Ottieni full text di un articolo CC
curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/document/211124"

# Pattern frontend: lista → click → fetch full text
const list = await fetch('/api/source/normattiva/documents?category=cc');
const docId = list.documents[0].id;
const full = await fetch(`/api/document/${docId}`);
console.log(full.full_text);  // rendering immediato

Recent Documents

GET /api/recent-documents

Ultimi documenti importati (cronologia harvest).

Query params

ParamTypeDescription
limitintegerDefault 20.

Stats

GET /api/stats

Statistiche aggregate del database (IT + UAE corpus). I numeri sono live al momento della chiamata.

{
  "total_documents": 648931,
  "total_chunks": 3920561,
  "total_entities": 637000,
  "chunks_uae": 28379,
  "sources": {/* breakdown per source — 67 fonti totali */},
  "last_harvest": "2026-05-20T05:30:00"
}

Per stats per-modulo: GET /api/modules/{id} (con counts live). Per stats per-source: GET /api/sources.

Articles

GET /api/articles/{article_number}

Lookup diretto di un articolo per numero (es. /api/articles/2473 per art. 2473 CC).

Countries v25.96

GET /api/countries

Lista paesi supportati dal corpus con stats. Usato da DocZoom Settings per popolare il selettore Country.

Response example

{
  "countries": [
    {"code": "IT", "name": "Italia", "docs": 648095, "sources": 61, "modules": 10},
    {"code": "AE", "name": "United Arab Emirates", "docs": 836, "sources": 6, "modules": 5}
  ]
}

Reference Lookup

GET /api/reference/{normalized_ref}

Lookup di un riferimento normativo o giurisprudenziale già normalizzato (es. art-2473-cc, cass-civ-12345-2023, dlgs-74-2000-art-2). Ritorna il documento + chunks principali.

Example

curl -H "X-API-Key: $KEY" \
  https://bancadati.doczoom.ai/api/reference/art-2473-cc

Response shape

{
  "reference": "art-2473-cc",
  "document": {"id": 12345, "title": "Art. 2473 c.c. – Recesso del socio", "source": "normattiva"},
  "chunks": [/* top chunks */]
}

Reference History

GET /api/reference/{normalized_ref}/history

Cronologia delle versioni di un riferimento normativo (modifiche, abrogazioni, sostituzioni). Utile per verificare la vigenza di una norma a una data.

Example

curl -H "X-API-Key: $KEY" \
  https://bancadati.doczoom.ai/api/reference/art-18-statuto-lavoratori/history

Reference Cited-By

GET /api/reference/{normalized_ref}/cited-by

Lista di documenti (sentenze, circolari, dottrina) che citano il riferimento. Costruito dal knowledge graph delle cross-reference estratte dai chunks.

Example

curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/reference/art-2473-cc/cited-by?limit=20"

Collections — list

GET /api/collections

Lista delle 66 collections professionali (profili commercialista, tributarista, avvocato civilista, notaio, consulente del lavoro + materie). 21 L1, 27 L2, 18 L3 (v25.101: aggiunte 7 sub-commercialista + 4 sub-tributarista). Cf. taxharvest/collections.yaml.

Profili professionali L1 esposti (7)

SlugNomeL2/L3 figli
commercialistaCommercialista12 (5 L2 + 7 L3)
avvocato-tributaristaAvvocato Tributarista4 L3
avvocato-civilistaAvvocato CivilistaL2
avvocato-penalistaAvvocato PenalistaL2
avvocato-amministrativistaAvvocato AmministrativistaL2
consulente-lavoroConsulente del LavoroL2
notaioNotaioL2

Sub-collections commercialista (esempio gerarchia)

L1  commercialista
├── L2  commercialista-fiscale
│   ├── L3  commercialista-dichiarazioni            // v25.101
│   ├── L3  commercialista-contenzioso-tributario   // v25.101
│   ├── L3  commercialista-ravvedimento-sanzioni    // v25.101
│   ├── L3  commercialista-internazionale           // v25.101
│   ├── L3  commercialista-cripto-assets            // v25.101
│   └── L3  commercialista-startup-pmi              // v25.101
├── L2  commercialista-contabile-bilancio
│   └── L3  commercialista-bilanci-revisione        // v25.101
├── L2  commercialista-societario
├── L2  commercialista-crisi-impresa
└── L2  commercialista-lavoro

Response shape

{
  "collections": [
    {
      "slug": "commercialista-fiscale",
      "name": "Commercialista — Fiscale",
      "level": "L1",
      "parent": null,
      "sources": ["ade_circolari", "ade_interpelli", "normattiva", "cassazione"],
      "docs_estimate": 340000
    }
    /* ... */
  ]
}

Collections — tree

GET /api/collections/tree

Struttura gerarchica L1 → L2 → L3 delle collections, pronta per il widget tree-view di DocZoom Studio.

Collections — detail

GET /api/collections/{slug}

Dettaglio di una singola collection: descrizione, sources, normattiva_codici, cassazione_macro_aree, parent/children, doc_count live.

Example

curl -H "X-API-Key: $KEY" \
  https://bancadati.doczoom.ai/api/collections/commercialista-iva

Collections — documents

GET /api/collections/{slug}/documents

Documenti appartenenti a una collection. Supporta paginazione (?limit=50&offset=0) e filtri (?source=ade_circolari&year=2026).

Norm Alerts v25.101 · NEW

Sistema di notifiche per cambiamenti normativi. L'utente registra "subscription" (per source, modulo, collection, keyword, reference o country) e l'API genera "events" quando nuovi documenti matchano i criteri. Architettura scan-on-poll: alla GET /api/alerts scan automatico dei documenti creati dopo l'ultima poll della subscription. Idempotente. UI built-in su /alerts.

GET /api/alerts

Lista degli eventi (notifiche) per l'API key corrente. Trigger scan automatico se scan=true (default).

Query params

FieldTypeDescription
unread_onlybooleanSolo eventi non letti (default false)
limitintegerDefault 50, max 500
offsetintegerPaginazione
scanbooleanDefault true. Se true, scan + create events PRIMA di ritornare

Response shape

{
  "events": [
    {
      "id": 42,
      "subscription": {"id": 1, "name": "Watch Circolari AdE", "sub_type": "source", "target": "ade_circolari"},
      "document_id": 656712,
      "title": "Circolare 14/E del 2026 — Forfettario 2026",
      "url": "https://...",
      "source": "ade_circolari",
      "country": "IT",
      "created_at": "2026-05-20T08:15:00Z",
      "read_at": null
    }
  ],
  "total": 128,
  "new_events_just_created": 3
}

Norm Alerts — create subscription

POST /api/alerts/subscriptions

Request body

FieldTypeDescription
sub_typestringTipo subscription: source | module | collection | keyword | reference | country
targetstringValore da osservare. Esempi: "ade_circolari" (source), "diritto-tributario" (module), "superbonus" (keyword), "art-2 D.Lgs. 74/2000" (reference), "AE" (country)
namestringOpzionale. Label friendly per la UI (es. "Watch Circolari AdE")
target_metaobjectOpzionale. Metadata addizionali (es. {"min_relevance": 0.5})

Example

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  https://bancadati.doczoom.ai/api/alerts/subscriptions \
  -d '{"sub_type":"keyword","target":"superbonus","name":"Watch superbonus"}'

Backfill 7-day

Al primo poll dopo la creazione, l'API ritorna anche gli eventi degli ultimi 7 giorni (UX: l'utente vede subito attività). Poi solo eventi nuovi.

Norm Alerts — list subscriptions

GET /api/alerts/subscriptions

Lista delle subscription attive per l'API key. Include conteggio eventi pendenti per ognuna.

Norm Alerts — toggle subscription

PATCH /api/alerts/subscriptions/{sub_id}?active=true|false

Attiva/disattiva una subscription senza eliminarla. Le subscription inattive non generano nuovi eventi.

Norm Alerts — delete subscription

DELETE /api/alerts/subscriptions/{sub_id}

Elimina definitivamente la subscription. Gli eventi storici restano in DB ma non saranno più mostrati.

Norm Alerts — mark event read

POST /api/alerts/{event_id}/read

Marca un singolo evento come letto (setta read_at = NOW()).

Norm Alerts — mark all read

POST /api/alerts/mark-all-read

Marca TUTTI gli eventi pendenti dell'utente come letti. Response: {"marked_read": N}.

Norm Alerts — stats

GET /api/alerts/stats

Response shape

{
  "subscriptions_active": 5,
  "subscriptions_total": 7,
  "events_total": 312,
  "events_unread": 12,
  "last_scan_at": "2026-05-20T08:15:00Z"
}

Audit Stats

GET /api/audit/stats?days=7

Aggregati audit log: tasso abstention, avg top_score, tasso citation hallucinations, success rate retrieval, ultimi N giorni. Endpoint per dashboard interna.

Response shape

{
  "period_days": 7,
  "total_queries": 12483,
  "abstention_rate": 0.034,
  "avg_top_score": 0.71,
  "hallucination_rate": 0.011,
  "reprompt_rate": 0.16,
  "factuality_flag_rate": 0.04
}

Audit Recent

GET /api/audit/recent?limit=50&abstained_only=false

Ultime N entry dell'audit_log (query, top_score, citation_hallucinations, factuality_issues, timing_ms). Per debug e fine-tuning.

Audit Analytics

GET /api/audit/analytics?group_by=source|module|day

Aggregati per dimensione (source citata, modulo richiesto, giorno). Restituisce time series + distribuzione.

Scheduler Status v25.101

GET /api/scheduler/status

Stato dello scheduler per ogni source: ultima ingestion, ore da ultima, cron schedule, country, ecc. Tutte le 67 fonti devono apparire con hours_since_last <= 48. Sorgente di verità per "tutte le fonti aggiornate 1×/giorno?".

Response shape

{
  "sources": [
    {
      "source": "ade_circolari",
      "country": "IT",
      "last_doc_at": "2026-05-20T08:15:00Z",
      "hours_since_last": 3,
      "scheduled": true,
      "cron_hint": "daily 08:15 UTC",
      "is_stale": false
    }
    /* ... 66 più ... */
  ],
  "stale_sources": [],
  "stale_threshold_hours": 48
}

Health — Sources freshness

GET /api/health/sources

Health check sulle source: ritorna HTTP 200 se tutte le 67 sources hanno ingestion entro 48h, HTTP 207 se 1-2 stale, HTTP 503 se ≥3 stale. Per integrazione UptimeRobot / Healthchecks.io.

Health — Cloudflare Proxy

GET /api/health/proxy

Stato del Cloudflare Worker proxy per i domini gov bloccati (normattiva.it, gazzettaufficiale.it, italgiure.giustizia.it, giustizia-amministrativa.it, eur-lex.europa.eu). Ritorna HTTP 200 se tutti i 5 domini sono raggiungibili via proxy, 207 se 1-2 down, 503 se ≥3 down.

Response shape

{
  "proxy_url": "https://taxharvest-proxy.dilan-80e.workers.dev",
  "domains": [
    {"domain": "italgiure.giustizia.it", "status": 200, "latency_ms": 340},
    {"domain": "normattiva.it", "status": 200, "latency_ms": 512}
    /* ... */
  ],
  "fail_count": 0,
  "last_check_at": "2026-05-20T06:30:00Z"
}

Tools — list

GET /api/tools

Schema vivo dei tools real-time disponibili (VIES P.IVA, Codice Fiscale, cambio valuta BCE, ecc.) per il routing di /api/doczoom/tool e /api/tool/{tool_name}. Usato dal frontend per popolare bottoni "verifica P.IVA", "calcola CF", ecc.

Response shape

{
  "tools": [
    {"name": "vies", "label": "Verifica P.IVA UE (VIES)", "params": ["country", "vat_number"]},
    {"name": "codice_fiscale", "label": "Calcolo Codice Fiscale", "params": ["name", "surname", "birth_date", "birth_place", "gender"]},
    {"name": "exchange_rate", "label": "Cambio valuta BCE", "params": ["from", "to", "date"]}
  ]
}

Cassazione — full corpus v25.104

GET /api/cassazione

Lista delle sentenze Corte di Cassazione (336.824 docs: civile, penale, costituzionale, relazioni Massimario). Shortcut di GET /api/legal-judgments?authority=cassazione.

Query params

FieldTypeDescription
courtstringFiltro libero su title (es. ?court=Civile, ?court=Penale, ?court=SU)
yearintegerFiltro anno (es. ?year=2024)
partiesstringSubstring match su title (parti)
qstringFull-text su title
page / per_pageintegerPaginazione (default 1 / 20, max 100)

Example

curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/cassazione?court=Civile&year=2024&per_page=10"

Cassazione — lookup specifico

GET /api/cassazione/{numero}/{anno}

Lookup di una Cassazione specifica per numero+anno. Match su pattern "n. NUMERO/ANNO" nel title. Ritorna lista di match (di solito 1, ma può essere >1 se ci sono ordinanze + sentenze con stesso numero).

Example

curl -H "X-API-Key: $KEY" https://bancadati.doczoom.ai/api/cassazione/12345/2024
# → { numero, anno, matches: [{ id, title, court, year, case_number, ... }] }

404 quando non trovata

HTTP 404
{ "error": "cassazione_not_found", "numero": 99999999, "anno": 2024 }

TAR — Tribunali Amministrativi Regionali

GET /api/tar

Lista sentenze TAR (242.019 provvedimenti, 30 sedi regionali). Shortcut di ?authority=tar.

Query params

FieldTypeDescription
sedestringSede TAR (es. ROMA, MILANO, NAPOLI, LATINA, BARI, ecc. — 30 sedi totali). Match su title.
yearintegerFiltro anno
parties / qstringMatch su title

Example

curl -H "X-API-Key: $KEY" \
  "https://bancadati.doczoom.ai/api/tar?sede=ROMA&year=2026&per_page=20"

Consiglio di Stato + CGA + Adunanza Plenaria

GET /api/consiglio-stato

Lista decisioni CdS, CGARS e Adunanza Plenaria (~20.575 docs). Shortcut di ?authority=cds.

Example

curl -H "X-API-Key: $KEY" "https://bancadati.doczoom.ai/api/consiglio-stato?year=2026"

Corte Costituzionale

GET /api/corte-costituzionale

Sentenze, ordinanze, decreti Corte Cost. (3.808 docs). Shortcut di ?authority=corte-costituzionale (alias ?authority=cost).

CGUE — Corte di Giustizia UE

GET /api/cgue

Sentenze + comunicati IT della Corte di Giustizia dell'Unione Europea (1.410 docs).

CEDU — Corte Europea Diritti Umani

GET /api/cedu

Sentenze CEDU (HUDOC) — 9 docs (corpus in espansione).

Giustizia Tributaria + Massimario CGT

GET /api/giustizia-tributaria

Massimario delle Corti di Giustizia Tributaria (1.112 massime). Coverage CGT di primo e secondo grado.

ABF — Arbitro Bancario Finanziario

GET /api/abf

Decisioni dell'Arbitro Bancario Finanziario (280 docs). Risoluzione stragiudiziale controversie banca-cliente.

AGCM — Antitrust

GET /api/agcm

Bollettini AGCM (808 docs): abuso posizione dominante, intese restrittive, concentrazioni, pratiche commerciali scorrette.

AGCOM — Autorità Comunicazioni

GET /api/agcom

Delibere AGCOM (537 docs): TLC, audiovisivo, postale, copyright digitale.

🇦🇪 Sentenze UAE (ADGM + DIFC combinate)

GET /api/sentenze-uae

Lista combinata sentenze UAE court (102 docs: 80 ADGM CFI + 22 DIFC). Shortcut di ?country=AE.

Query params

FieldTypeDescription
courtstringFiltro libero (es. ?court=ARB per arbitration cases)
year / parties / qstringStandard

Example

curl -H "X-API-Key: $KEY" "https://bancadati.doczoom.ai/api/sentenze-uae?per_page=20"

🇦🇪 ADGM — Abu Dhabi Global Market

GET /api/adgm

Sentenze ADGM Courts (80 docs CFI) — Court of First Instance Abu Dhabi Global Market. Common law in lingua inglese. Shortcut di ?authority=adgm&country=AE.

🇦🇪 DIFC — Dubai International Financial Centre

GET /api/difc

Sentenze DIFC Courts (22 docs) — Court of First Instance + Court of Appeal + Small Claims Tribunal Dubai. Common law in inglese. Shortcut di ?authority=difc&country=AE.

Health Check

GET /health

Uptime check (no auth richiesta). Latenza tipica ~1ms.

{"status": "ok", "timestamp": "2026-04-29T11:30:00Z"}

System Info

GET /api/system-info

Info sistema (versione, uptime, container memory).


TaxHarvest API · v25.110 · bancadati.doczoom.ai · Last updated 2026-06-01 · 65 codici Normattiva art-by-art · 67 fonti (61 IT + 6 UAE) · 648K+ docs · 3.92M+ chunks IT + 28K UAE · 18 moduli · 66 collections · 13 endpoint giurisprudenza dedicati · ⚡ fast-path lookup sentenze 200ms · 📄 document viewer /doc/{id} (⬇ PDF/Word)