{
  "openapi": "3.1.0",
  "info": {
    "title": "E-Invoice from PDF – try-out API",
    "version": "1.0.0",
    "description": "Turn a PDF invoice into a validated XRechnung or ZUGFeRD e-invoice, and validate existing e-invoices.\n\n**Conversion is asynchronous:** `POST /conversions` returns `202` with an `id`; poll `GET /conversions/{id}` until `status` is `done`. A valid conversion lists its `files`.\n\n**A PDF that already is an e-invoice** (ZUGFeRD with a valid embedded XML) is not converted again: it is checked like `POST /validations`, the result says `alreadyValid: true` with that `validation`, and it does not use up the free conversion. With `format=xrechnung` the XRechnung is made from its XML. An incomplete one lists `clarifications`: answer them with `POST /conversions/{id}/answers`, which reruns the conversion without a second LLM call.\n\n**Limits (try-out):** one conversion per connection (IPv4, or IPv6 /64) within 30 days, one per file, a daily cap over all users; 5 validations per connection per hour. Results are deleted after 24 hours. Production access with API keys and your own quota: get in touch on the start page.\n\nField names follow EN 16931 (Appendix A, camelCase); every value carries its BT code in the clarifications.\n\n**Request IDs:** every response carries an `X-Request-ID` header. On an error (status 400 and above), quote it when you contact support."
  },
  "servers": [{ "url": "/api/v1" }],
  "paths": {
    "/conversions": {
      "post": {
        "operationId": "createConversion",
        "summary": "Convert a PDF invoice",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": { "type": "string", "format": "binary", "description": "The PDF invoice, at most 10 MB. A ZUGFeRD PDF is recognised and checked instead of converted." },
                  "format": { "type": "string", "enum": ["zugferd", "xrechnung"], "default": "zugferd", "description": "zugferd: PDF/A-3 with embedded XML (EN 16931). xrechnung: CII XML (XRechnung 3.0)." },
                  "email": { "type": "string", "format": "email", "description": "Optional. Given, we may contact you about the product; it is never used to send results." },
                  "consent": { "type": "boolean", "default": false, "description": "May we keep the PDF as a test example?" }
                }
              }
            }
          }
        },
        "responses": {
          "202": { "description": "Accepted and queued.", "headers": { "Location": { "schema": { "type": "string" } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversion" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "413": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Limit" }
        }
      }
    },
    "/conversions/{id}": {
      "get": {
        "operationId": "getConversion",
        "summary": "Status and result of a conversion",
        "parameters": [{ "$ref": "#/components/parameters/id" }],
        "responses": {
          "200": { "description": "The conversion.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversion" } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/conversions/{id}/answers": {
      "post": {
        "operationId": "answerConversion",
        "summary": "Supply missing fields and rerun",
        "description": "The body is a partial invoice in the JSON input form: the `paths` of each clarification, nested. Answers only fill fields the document lacks; a value the document states wins and is listed under `ignored`. Amounts are strings, dates YYYY-MM-DD. Answers accumulate across calls. At most 5 runs per conversion.",
        "parameters": [{ "$ref": "#/components/parameters/id" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "additionalProperties": true },
              "example": { "buyerReference": "04011000-12345-34", "seller": { "postalAddress": { "countryCode": "DE" }, "electronicAddress": "rechnung@example.com" } }
            }
          }
        },
        "responses": {
          "202": { "description": "Queued again.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversion" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "409": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/conversions/{id}/files/{file}": {
      "get": {
        "operationId": "getConversionFile",
        "summary": "Download the e-invoice",
        "parameters": [
          { "$ref": "#/components/parameters/id" },
          { "name": "file", "in": "path", "required": true, "schema": { "type": "string", "enum": ["zugferd.pdf", "xrechnung.xml"] } }
        ],
        "responses": {
          "200": { "description": "The file.", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } }, "application/xml": { "schema": { "type": "string" } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/validations": {
      "post": {
        "operationId": "validateInvoice",
        "summary": "Validate an existing XRechnung or ZUGFeRD",
        "description": "XML (CII or UBL) or PDF. XRechnung goes through the KoSIT validator; PDFs and EN 16931 XML through Mustang, and the XML a PDF embeds through KoSIT as well when it is XRechnung. The response also contains the invoice read from the file, in the JSON input form.",
        "requestBody": {
          "required": true,
          "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["file"], "properties": { "file": { "type": "string", "format": "binary" } } } } }
        },
        "responses": {
          "200": { "description": "The report; `valid` says whether it passed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Validation" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "413": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Limit" },
          "502": { "description": "A validator failed to run; retry later.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Validation" } } } }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "id": { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^[0-9a-f]{32}$" } }
    },
    "responses": {
      "Error": { "description": "Error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Limit": { "description": "A try-out limit is used up.", "headers": { "Retry-After": { "schema": { "type": "integer" } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error", "message"],
        "properties": {
          "error": { "type": "string", "examples": ["limit_ip", "limit_file", "limit_daily", "limit_validations", "not_pdf", "not_invoice_file", "no_file", "too_large", "bad_email", "bad_answers", "not_answerable", "not_found", "internal"] },
          "message": { "type": "string" }
        }
      },
      "Conversion": {
        "type": "object",
        "required": ["id", "status", "valid", "alreadyValid", "rerunsLeft", "links"],
        "properties": {
          "id": { "type": "string" },
          "status": { "type": "string", "enum": ["queued", "running", "done"] },
          "valid": { "type": "boolean", "description": "Accepted by KoSIT and Mustang. Files exist only when true." },
          "invoices": { "type": "integer", "description": "Invoices the document holds. The try-out converts the one starting on the earliest page; a notice says so when there are more." },
          "errors": { "type": "array", "items": { "type": "string" } },
          "notices": { "type": "array", "items": { "type": "string" } },
          "ignored": { "type": "array", "items": { "type": "string" }, "description": "Answers not used because the document states the value." },
          "findings": { "type": "array", "items": { "type": "string" }, "description": "Plausibility and validator findings, \"RULE: message\"." },
          "clarifications": { "type": "array", "items": { "$ref": "#/components/schemas/Clarification" } },
          "files": { "type": "object", "additionalProperties": { "type": "string" }, "description": "File name → download URL." },
          "alreadyValid": { "type": "boolean", "description": "The upload already was a valid e-invoice: nothing was extracted, and it did not use up the free conversion." },
          "validation": { "$ref": "#/components/schemas/Validation", "description": "The check of the e-invoice the upload embeds; set whenever it embeds one, valid or not." },
          "rerunsLeft": { "type": "integer" },
          "links": { "type": "object", "additionalProperties": { "type": "string" } }
        }
      },
      "Clarification": {
        "type": "object",
        "properties": {
          "field": { "type": "string", "examples": ["BT-10"] },
          "label": { "type": "string" },
          "flag": { "type": "string", "description": "The equivalent CLI flag." },
          "scope": { "type": "string", "enum": ["invoice", "seller"] },
          "paths": { "type": "array", "items": { "type": "string" }, "description": "JSON input paths that answer it; \"[]\" marks an array element." },
          "oneOf": { "type": "boolean", "description": "true: any single path answers it (e.g. tax number or VAT ID). false: every path is needed." }
        }
      },
      "Validation": {
        "type": "object",
        "properties": {
          "file": { "type": "string" },
          "syntax": { "type": "string", "enum": ["cii", "ubl", "pdf"] },
          "profile": { "type": "string", "description": "BT-24 specification identifier." },
          "valid": { "type": "boolean" },
          "errors": { "type": "array", "items": { "type": "string" } },
          "kosit": { "$ref": "#/components/schemas/Report" },
          "mustang": { "$ref": "#/components/schemas/Report" },
          "invoice": { "type": "object", "description": "The invoice read from the file, in the JSON input form (EN 16931 Appendix A names)." }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "valid": { "type": "boolean" },
          "errors": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } },
          "warnings": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } },
          "engine": { "type": "string" },
          "scenario": { "type": "string" }
        }
      },
      "Finding": {
        "type": "object",
        "properties": {
          "rule_id": { "type": "string" },
          "message": { "type": "string" },
          "location": { "type": "string" },
          "severity": { "type": "string" },
          "bt": { "type": "string" },
          "jsonPath": { "type": "string" }
        }
      }
    }
  }
}
