{
  "openapi": "3.1.0",
  "info": {
    "title": "Data Alchemy Document Extraction API",
    "version": "1.0.0",
    "summary": "Estrae dati strutturati e validati da fatture, DDT, ordini, contratti e listini.",
    "description": "API REST di Intelligent Document Processing (IDP) di Data Alchemy. Invii un documento (PDF nativo, PDF scansionato, immagine o XML FatturaPA) e ricevi JSON tipizzato con testata, righe di dettaglio, totali ed esito della validazione sulle anagrafiche dell'ERP: 99,8% di accuratezza dichiarata per campo (misurata con Claude); con Claude Sonnet o superiore la lettura richiede in media circa 12 secondi per un documento di una pagina e circa 18 per due pagine. Il flusso è asincrono: POST del documento, poi webhook `document.processed` (consigliato) oppure GET del risultato. Lo schema di output è identico per tutti i tipi di documento, quindi il mapping verso il gestionale si scrive una volta sola e si riusa. Modello a licenze (Basic, Business o Enterprise) con crediti a consumo, preventivo su richiesta: https://www.data-alchemy.ai/it/pricing. Hosting e conservazione dei dati nell'Unione Europea, conformi al GDPR; con Data Alchemy AI e con i provider europei l'elaborazione resta in Europa, con Claude e GPT i documenti sono elaborati dai rispettivi provider sotto DPA.",
    "termsOfService": "https://www.data-alchemy.ai/it/contatti",
    "contact": {
      "name": "Data Alchemy — CDBKR Srl",
      "email": "info@data-alchemy.ai",
      "url": "https://www.data-alchemy.ai/it/sviluppatori-api"
    }
  },
  "externalDocs": {
    "description": "Documentazione API per sviluppatori (IT) / Developer API reference (EN)",
    "url": "https://www.data-alchemy.ai/it/sviluppatori-api"
  },
  "servers": [
    {
      "url": "https://api.data-alchemy.ai/v1",
      "description": "Produzione"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Documents",
      "description": "Invio dei documenti e recupero dei dati estratti."
    },
    {
      "name": "Webhooks",
      "description": "Notifiche event-driven a fine elaborazione."
    }
  ],
  "paths": {
    "/documents": {
      "post": {
        "tags": [
          "Documents"
        ],
        "operationId": "submitDocument",
        "summary": "Invia un documento e avvia l'estrazione",
        "description": "Invia un documento (PDF, XML, immagine) e avvia l'estrazione. Restituisce subito un `id` e lo stato `processing`: l'elaborazione è asincrona. Il risultato si recupera con `GET /v1/documents/{id}` oppure, meglio, lasciando che sia il webhook `document.processed` a notificarlo.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "document_type"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Il documento da elaborare: PDF nativo, PDF scansionato, immagine o XML FatturaPA."
                  },
                  "document_type": {
                    "type": "string",
                    "enum": [
                      "invoice",
                      "delivery_note",
                      "order",
                      "contract",
                      "price_list"
                    ],
                    "description": "Tipo di documento da estrarre."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Documento accettato e in elaborazione.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentAccepted"
                },
                "example": {
                  "id": "doc_8a7f2c91",
                  "status": "processing",
                  "document_type": "invoice",
                  "created_at": "2026-06-04T09:12:33Z",
                  "webhook_url": "https://yourapp.example.com/hooks/data-alchemy"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "listDocuments",
        "summary": "Elenca i documenti elaborati",
        "description": "Elenca i documenti elaborati con filtri per stato, tipo e intervallo di date.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "processing",
                "completed"
              ]
            },
            "description": "Filtra per stato di elaborazione."
          },
          {
            "name": "document_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "invoice",
                "delivery_note",
                "order",
                "contract",
                "price_list"
              ]
            },
            "description": "Filtra per tipo di documento."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inizio dell'intervallo di date (incluso)."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Fine dell'intervallo di date (inclusa)."
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco dei documenti che soddisfano i filtri.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Document"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/documents/{id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "operationId": "getDocument",
        "summary": "Recupera i dati estratti di un documento",
        "description": "Recupera lo stato e i dati estratti e validati di un documento già inviato. Finché `status` è `processing` il campo `data` non è ancora popolato.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "L'id restituito dalla POST di invio, ad esempio `doc_8a7f2c91`.",
            "example": "doc_8a7f2c91"
          }
        ],
        "responses": {
          "200": {
            "description": "Risultato pronto: dati estratti e validati.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "example": {
                  "id": "doc_8a7f2c91",
                  "status": "completed",
                  "confidence": 0.998,
                  "data": {
                    "document_type": "invoice",
                    "header": {
                      "supplier": {
                        "name": "Rossi Forniture S.r.l.",
                        "vat_number": "IT01234567890"
                      },
                      "invoice_number": "2026/00417",
                      "issue_date": "2026-05-28",
                      "currency": "EUR"
                    },
                    "line_items": [
                      {
                        "sku": "ART-0042",
                        "description": "Cartone 30x20x15",
                        "quantity": 12,
                        "unit_price": 8.5,
                        "total": 102,
                        "vat_rate": 22
                      }
                    ],
                    "totals": {
                      "net": 102,
                      "vat": 22.44,
                      "gross": 124.44
                    },
                    "validation": {
                      "status": "validated",
                      "erp_match": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhooks": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "registerWebhook",
        "summary": "Registra un endpoint per gli eventi document.processed",
        "description": "Registra un endpoint che riceverà gli eventi `document.processed` in tempo reale, evitando il polling. Ogni consegna è firmata con HMAC SHA-256 nell'header `X-Data-Alchemy-Signature`: ricalcola la firma sul body grezzo e confrontala a tempo costante prima di leggere il payload. Le consegne fallite vengono ritentate automaticamente con backoff crescente.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "L'endpoint HTTPS che riceverà la POST.",
                    "example": "https://yourapp.example.com/hooks/data-alchemy"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook registrato.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "webhooks": {
    "document.processed": {
      "post": {
        "operationId": "onDocumentProcessed",
        "summary": "Notifica di documento elaborato",
        "description": "Data Alchemy invia questa POST all'URL registrato appena l'elaborazione termina. Verifica sempre l'header `X-Data-Alchemy-Signature` prima di leggere il payload.",
        "parameters": [
          {
            "name": "X-Data-Alchemy-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "HMAC SHA-256 del corpo grezzo della richiesta, calcolato con il tuo secret, nel formato `sha256=<hex>`.",
            "example": "sha256=…"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event": {
                    "type": "string",
                    "const": "document.processed"
                  },
                  "id": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "const": "completed"
                  },
                  "confidence": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  },
                  "data": {
                    "$ref": "#/components/schemas/ExtractedData"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Restituisci 2xx per confermare la ricezione. In assenza di 2xx la consegna viene ritentata con backoff crescente."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key trasmessa nell'header `Authorization: Bearer <API_KEY>`. Le chiavi si generano dalla console e vanno conservate lato server (variabile d'ambiente o secret manager), mai esposte nel browser."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "API key mancante, scaduta o non valida.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "unauthorized",
                "message": "Invalid API key."
              }
            }
          }
        }
      },
      "Unprocessable": {
        "description": "Documento non leggibile o formato non supportato.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "unprocessable_document",
                "message": "Document could not be read."
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit superato: riprova con backoff esponenziale, rispettando l'header `Retry-After`.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Secondi da attendere prima di riprovare."
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "rate_limit_exceeded",
                "message": "Too many requests. Retry after 30s."
              }
            }
          }
        }
      }
    },
    "schemas": {
      "DocumentAccepted": {
        "type": "object",
        "description": "Risposta 202 all'invio di un documento.",
        "properties": {
          "id": {
            "type": "string",
            "example": "doc_8a7f2c91"
          },
          "status": {
            "type": "string",
            "const": "processing"
          },
          "document_type": {
            "type": "string",
            "enum": [
              "invoice",
              "delivery_note",
              "order",
              "contract",
              "price_list"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "webhook_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Document": {
        "type": "object",
        "description": "Stato di un documento e, quando pronto, i dati estratti.",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "completed"
            ]
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Livello di confidenza complessivo dell'estrazione."
          },
          "data": {
            "$ref": "#/components/schemas/ExtractedData"
          }
        }
      },
      "ExtractedData": {
        "type": "object",
        "description": "Schema di output, identico per tutti i tipi di documento: il mapping verso l'ERP si scrive una sola volta.",
        "properties": {
          "document_type": {
            "type": "string",
            "enum": [
              "invoice",
              "delivery_note",
              "order",
              "contract",
              "price_list"
            ],
            "description": "Tipo di documento classificato dall'AI."
          },
          "header": {
            "$ref": "#/components/schemas/Header"
          },
          "line_items": {
            "type": "array",
            "description": "Righe di dettaglio. È la parte tecnicamente più difficile e quella che genera il risparmio: una fattura da quaranta righe corrisponde a quaranta inserimenti manuali evitati.",
            "items": {
              "$ref": "#/components/schemas/LineItem"
            }
          },
          "totals": {
            "$ref": "#/components/schemas/Totals"
          },
          "validation": {
            "$ref": "#/components/schemas/Validation"
          }
        }
      },
      "Header": {
        "type": "object",
        "description": "Dati di testata: anagrafica fornitore/cliente, partita IVA, numero documento, date e valuta.",
        "properties": {
          "supplier": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "example": "Rossi Forniture S.r.l."
              },
              "vat_number": {
                "type": "string",
                "example": "IT01234567890"
              }
            }
          },
          "invoice_number": {
            "type": "string",
            "example": "2026/00417"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "example": "2026-05-28"
          },
          "currency": {
            "type": "string",
            "example": "EUR"
          }
        }
      },
      "LineItem": {
        "type": "object",
        "properties": {
          "sku": {
            "type": "string",
            "description": "Codice articolo.",
            "example": "ART-0042"
          },
          "description": {
            "type": "string",
            "example": "Cartone 30x20x15"
          },
          "quantity": {
            "type": "number",
            "example": 12
          },
          "unit_price": {
            "type": "number",
            "example": 8.5
          },
          "total": {
            "type": "number",
            "example": 102
          },
          "vat_rate": {
            "type": "number",
            "description": "Aliquota IVA in percentuale.",
            "example": 22
          }
        }
      },
      "Totals": {
        "type": "object",
        "description": "Totali calcolati e ricontrollati.",
        "properties": {
          "net": {
            "type": "number",
            "description": "Imponibile.",
            "example": 102
          },
          "vat": {
            "type": "number",
            "description": "Imposta.",
            "example": 22.44
          },
          "gross": {
            "type": "number",
            "description": "Totale documento.",
            "example": 124.44
          }
        }
      },
      "Validation": {
        "type": "object",
        "description": "Esito della validazione in tempo reale sull'anagrafica dell'ERP. È il controllo che un OCR, per definizione, non può fare.",
        "properties": {
          "status": {
            "type": "string",
            "example": "validated"
          },
          "erp_match": {
            "type": "boolean",
            "description": "Vero se fornitore e articoli esistono nell'anagrafica del gestionale.",
            "example": true
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}