{"openapi":"3.1.0","info":{"title":"FacturX API - Moteur de reparation Factur-X EN16931","description":"Moteur de reparation EN16931 document-centric pour editeurs ERP verticaux, logiciels metiers sectoriels a flux facturants et integrateurs non-Odoo. Genere des candidats Factur-X et des preuves de validation pour les flux supportes. La soumission, l'acceptation Plateforme Agreee et la conformite fiscale finale restent hors perimetre sans evenement PA verifie.\n\n## Versioning policy\n\n- ``/api/v1`` is the stable public API. Only **additive (non-breaking)** changes ship under this prefix: new fields, new endpoints, new error codes, new enum values on open enums.\n- **Breaking changes are NEVER applied to ``/api/v1`` in place.** They require a new versioned prefix (``/api/v2``) with explicit migration notice and a deprecation window on ``/api/v1``.\n- ``/meta`` exposes ``public_api_version``, ``product_truth_contract_version`` and ``conversion_input_recipe_version`` verbatim so a client can pin against the contract surface without parsing the OpenAPI document.\n- Plateforme Agreee acceptance is **never inferred** from any response: PA lifecycle remains an external event that must arrive via a documented PA lifecycle channel.","contact":{"name":"Factur-X Validation API","url":"https://facturxapi.com/contact"},"license":{"name":"MIT"},"version":"1.0.0","x-release":"f144c6684575da8113a2d9120d00664043dfa3da"},"paths":{"/api/v1/convert":{"post":{"tags":["convert"],"summary":"Convert invoice data or PDF to Factur-X PDF/A-3","description":"Attempts to generate a Factur-X PDF/A-3 candidate from a PDF invoice or a complete structured `invoice_data` payload and returns validation evidence.\n\n`/convert` has two public deliverables, selected with the `output` form field:\n\n- `output=facturx_pdfa3` (default): the generated Factur-X PDF/A-3 with embedded XML. Upload a PDF invoice as visual carrier, or send a complete `invoice_data` payload so the API can render the carrier from the same structured invoice source before PDF/A-3 packaging. This deliverable is strict: if the requested target is verified but PDF/A-3 packaging fails or is unavailable, the call fails closed with `503 requested_output_unavailable` (quota refunded) — it never silently degrades to an XML-only success.\n- `output=xml_cii`: only the generated CII XML, normally in the requested `options.output_profile`, returned in `result.xml`. When `invoice_data.payer` is present, the effective profile is promoted to `EXTENDED` because the payer block is not available in lower Factur-X profiles; `result.targetProfile` is authoritative for the profile actually emitted. France 2026 / FNFE-MPE checks are added when requested. No PDF/A-3 packaging is performed and the deliverable is a CII XML file, **not** a Factur-X document. With a full `invoice_data` payload, the `file` upload is optional; the same canonical `validationReadiness` verdict, validation pipeline and quota rules apply (`success=true` only when the requested target is passed in `validationReadiness`; 1 processed invoice per final call, refunded when no deliverable is produced).\n\n`output` is the only deliverable selector. The legacy `options.mode=\"xml_only\"` knob no longer selects the deliverable on final conversions: without `output=xml_cii` it is rejected with `400 invalid_options` (dry-run diagnostics are exempt — the public scanner uses it).\n\nFor `output=facturx_pdfa3`, a valid Factur-X CII XML (BASIC or EN16931) is accepted as the sole source; its carrier is rendered from the XML data. A validated UBL Invoice/CreditNote is also accepted when every source field is supported by the strict UBL-to-CII mapper. Unrepresentable UBL fields return `422 ubl_source_mapping_unsupported` instead of being dropped.\n\n`/convert` has five public input modes:\n\n- PDF document extraction: send a PDF file and let the service extract invoice data.\n- Factur-X CII XML source: upload a valid Factur-X CII XML (guideline BASIC or EN16931) without a PDF. The XML is validated, mapped without inventing any value, re-serialized as the EN16931 candidate (a BASIC source is emitted as EN16931: `result.extraction.sourceProfile` keeps the submitted profile, `result.targetProfile` is the written profile), and the visual carrier is rendered from that same data before PDF/A-3 packaging. It is converted exactly as submitted: `invoice_data`, `invoice_patch`, seller/buyer context and profile reuse are refused with `422 cii_xml_source_overlay_unsupported`. Header-only CII (MINIMUM, BASIC WL) returns `422 cii_source_profile_header_only`; ZUGFeRD 1.0 and other guidelines return `422 cii_source_unsupported`; XML declaring a DOCTYPE/entities returns `400 xml_security_error`; any other non-UBL XML keeps `415 unsupported_media_type`.\n- Full structured source: send `invoice_data`; it is a complete ERP invoice payload and PDF text parsing is skipped. `invoice_data.business_process` is explicit business context emitted as BT-23; it is never inferred from the target, profile, amounts or VAT. When omitted, BT-23 stays absent. France 2026 readiness reports that omission as an actionable non-blocking input; local EN16931 / France 2026 generation remains unaffected and no default is invented. BT-24 is separate and derived from the effective output profile. Supplying `invoice_data.payer` emits EXT-FR-FE-BG-02 and therefore promotes the effective output profile to `EXTENDED`, even if a lower `options.output_profile` was requested; read `result.targetProfile` for the effective profile.\n- Stateless inline complements / request-context complements: send `invoice_patch`, `seller_context` and/or `buyer_context` with the document. These fields only complete explicitly supported gaps and never silently overwrite visible PDF/XML data.\n- Explicit tenant-scoped persistent profile reuse: send `profile_reuse=explicit` with tenant-scoped `issuer_id`/`seller_profile_id` and/or `client_id`/`buyer_profile_id`. Saved profile identity/version is included in the request identity. A selector without `profile_reuse=explicit` is rejected instead of silently loading a profile from another tenant.\n\nSaved profile misuse fails closed: missing opt-in returns `profile_reuse_requires_explicit_opt_in`, missing selectors for `profile_reuse=explicit` return `profile_reuse_selector_required`, disagreeing selector aliases return `profile_selector_conflict`, unknown tenant-scoped records return `seller_profile_not_found` or `buyer_profile_not_found`, no profile is silently loaded from another tenant, and profile/request-context conflicts return `profile_inline_context_conflict`.\n\nThe canonical preparation/diagnostic surface is the `dry_run=true` query parameter. It runs without monthly quota consumption and produces no final deliverable. Legacy multipart `dry_run` and `preview` aliases remain accepted for compatibility; every explicitly supplied control must agree or the request fails with `400 conflicting_dry_run_parameters` before conversion and quota reservation. Dry-run accepts PDF uploads and XML uploads for validation diagnostics, but XML dry-run does not package a final Factur-X PDF. Dry-run responses expose Product Truth `requirements`, `fieldProvenance`, `validationTarget`, `validationReadiness`, and `conversionInputRecipe`; France 2026 responses additionally expose `targetPreflight`, while EN16931 responses omit that France-only contract. These fields let clients separate the requested target, EN16931 base readiness, France 2026 / FNFE-MPE runtime evidence for the effective pack (read `validationReadiness.frCtc` and `validationArtifacts` for the executed checks, and `/api/v1/meta` for selected/loaded runtime metadata; explicit rollbacks use their own real severities), and PA lifecycle status. Lifecycle fields keep artifact roles separate: `submittedSourceReadiness` is the uploaded source artifact, `candidateValidationReadiness` is a generated candidate when one was actually produced/validated, and `finalGeneratedValidation` is the final generated deliverable after generation/packaging. Clients must not collapse candidate or final evidence into submitted-source readiness, and must not infer final readiness from a dry-run candidate alone. A successful technical validation or conversion is not PA acceptance; `paAcceptance` stays `not_submitted` until a real PA lifecycle event exists.\n\nUse `validation_target=en16931` for a Factur-X EN16931 conversion. Use `validation_target=france_2026` for EN16931 plus the available France 2026 / FNFE-MPE checks. The response exposes the requested policy in `validationTarget` and the canonical executable verdict in `validationReadiness`; clients must not infer France readiness from `success` alone.\n\nFor `validation_target=france_2026`, dry-run also emits `targetPreflight`.\n`targetPreflight.exhaustive=true` means the API has generated/validated a\ncandidate, or has an equivalent deterministic proof, and the supported\nFrance 2026 checklist in `targetPreflight.requiredInputs`,\n`targetPreflight.beforeTransmissionInputs`, and `unsupportedBlockers` is\ncomplete for the supported contract. The matching `conversionInputRecipe`\nbuckets are the single source of truth; clients must not infer phases from\nseverity or localized validator text.\nIf the candidate probe is not exhaustive, clients must use the structured\n`targetPreflight.status`, `targetPreflight.exhaustive`, and blocker fields to\nrender product-approved copy, and must not present the partial checklist as\ncomplete. Unsupported target blockers stay visible in\n`targetPreflight.unsupportedBlockers` and make final `/convert` fail closed with\nno deliverable. An FNFE-MPE fatal blocker always keeps the submitted target and\n`validationReadiness.frCtc` blocked, with `success=false`. It does not, by\nseverity alone, decide whether already-generated corrective candidate bytes can\nbe retained. Retention requires exhaustive occurrence-level evidence that every\nexecuted fatal blocker maps one-to-one to a supported `beforeTransmissionInputs`\ncarrier with `blocksGeneration=false` and `blocksTransmission=true`, while\n`generationReadiness.status=ready` and no required generation blocker, API or\nproduct gap, out-of-scope blocker, non-runnable decision, identity collision, or\nmissing/malformed evidence remains. Otherwise `/convert` returns no deliverable.\nAn advisory-only france_2026 final\nconversion has no fatal blocker and can return `success=true` with\n`target.status=\"verified\"` / `validationReadiness.frCtc.status=\"passed\"` when\nthe generated Factur-X deliverable is technically exchangeable. The response\nmust still expose the France 2026 rule ids in\n`validationReadiness.frCtc.advisories` or `.blockers`; clients must not\ntranslate that into PA acceptance or a claim that every FNFE-MPE issue is\nresolved. Do not collapse all France 2026 issue ids into \"optional\": under\nthe current France CTC pack, BT-23, BT-34 / BR-FR-13,\nBT-49 / BR-FR-12, and BT-22 / BR-FR-05 PMT/PMD/AAB are ALL pinned fatal —\nthe submitted document is not France 2026-compliant without them, and they\nare required before France 2026 transmission (`beforeTransmissionInputs`).\nThat severity does not, by itself, block local generation: none of these six\nrules automatically blocks `/convert` from producing a candidate — only a\nspecific occurrence a producer has determined cannot be resolved with the\ndata present does that (`requiredInputs`, `blocksGeneration=true`). Under an\nexplicit 1.3.1 rollback, these same rules carry the rollback pack's own real\n(advisory) severities instead — never a newer pack's obligation simulated on\nthe older pack. None of BT-23/BT-34/BT-49/PMT/PMD/AAB are routing\nidentifiers except BT-34/BT-49 themselves.\n\nFrance 2026 target resolution is shared with `/validate`: explicit `validation_target=france_2026` (or legacy `validation_profile=fr_ctc`) fails clearly if not executable; legacy `auto&jurisdiction=FR` runs France 2026 checks when the runtime is available; `auto&jurisdiction=UNKNOWN` derives France 2026 only from seller/buyer `CountryID=FR` evidence; non-FR request jurisdiction with FR document evidence is reported as a `validationTarget` conflict rather than hidden as either France valid or France 2026 blockers. Legacy target controls still live in the `options` JSON for `/convert`: `validation_profile`, `jurisdiction`, `require_profile`, and `message_type`.\n\nFinal convert after a dry run (sealed `generation_*` options): the request's target must be the sealed one. Without `validation_target`, the server derives it from the request's own readable CII (an uploaded CII or a Factur-X PDF) with the dry run's rule. For a PDF without embedded XML it cannot, so send the target the dry run showed (`target.requested`); otherwise the call returns 409 `COMMAND_NOT_BOUND` naming that field.\n\nCurrent France 2026 / FNFE-MPE inline complements:\n\n- BT-23: `invoice_data.business_process` for full structured sources, or `invoice_patch.business_process` alongside a source document. Supply the actual billing frame explicitly; the API never defaults or infers this business value. The accepted values mirror the runtime-selected FNFE-MPE CII executable vocabulary (`B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9`). Omission leaves BT-23 unresolved (`requiredPolicy.resolutionStatus=user_input_required`) and is surfaced as a France 2026 before-transmission input (`beforeTransmissionInputs`); it does not by itself block local generation (`requiredPolicy.blocksConversion=false`) — supply it in the same `/convert` call to satisfy the submitted-document obligation.\n- BT-26: `invoice_patch.preceding_invoice.issue_date`, with optional matching `preceding_invoice.reference` for DI 0414-style credit-note corrections when BT-25 is already visible/proven.\n- BT-84: `invoice_patch.payment.iban` for a missing seller payment account on a document-derived conversion. It is a partial overlay, not a full `invoice_data` source.\n- BG-14: `invoice_patch.invoicing_period.start_date` / `end_date` for a document-derived billing period. Matching visible values are accepted; contradictions are rejected.\n- BT-34 / BR-FR-13: seller electronic address, required before France 2026 transmission, routing, and lifecycle-status exchanges; provide it through `seller_context.electronic_address` with `value` (max 125 chars) and alphanumeric `scheme_id` (2-20 chars).\n- BT-49 / BR-FR-12: buyer electronic address, required before France 2026 transmission, routing, and lifecycle-status exchanges; provide it through `buyer_context.electronic_address` with `value` (max 125 chars) and alphanumeric `scheme_id` (2-20 chars).\n- BT-22 / BR-FR-05 PMT/PMD/AAB: pinned fatal under the current FNFE-MPE Schematron pack (see `validationReadiness.frCtc` for the effective version and findings) — the submitted document is not France 2026-compliant without them and they are required before France 2026 transmission (`beforeTransmissionInputs`), but that does not by itself block local generation; not a routing identifier. Under an explicit 1.3.1 rollback these carry the rollback pack's own real (advisory) severity instead. Provide the notes through `seller_context.document_notes[]` (canonical recipe path) or `buyer_context.document_notes[]` (alternate accepted path) with a required UNCL4451 `subject_code` (BT-21) and non-empty `content` (max 500 chars). Untyped notes are rejected.\n\nExample inline context JSON:\n```json\n{\n  \"invoice_patch\": {\n    \"preceding_invoice\": {\"issue_date\": \"2025-08-31\"},\n    \"payment\": {\"iban\": \"FR7630006000011234567890189\"}\n  },\n  \"seller_context\": {\n    \"electronic_address\": {\"value\": \"99999123500014\", \"scheme_id\": \"0225\"},\n    \"document_notes\": [\n      {\"subject_code\": \"PMT\", \"content\": \"Indemnite forfaitaire de recouvrement de 40 EUR due en cas de retard de paiement\"}\n    ]\n  },\n  \"buyer_context\": {\n    \"electronic_address\": {\"value\": \"98765432100011\", \"scheme_id\": \"0225\"},\n    \"document_notes\": [\n      {\"subject_code\": \"AAB\", \"content\": \"Aucun escompte pour paiement anticipe\"}\n    ]\n  }\n}\n```\n\nFrance 2026 dry-run/final replay pattern: run the dry-run first, copy the\nexact `conversionInputRecipe.examplePayload` roots from that response, and\nreplay them only when `targetPreflight.exhaustive=true` and\n`targetPreflight.unsupportedBlockers` is empty. If the preflight is incomplete\nor unsupported blockers remain, treat the payload as diagnostic-only and expose\nthose blockers instead of launching final `/convert`.\n```bash\ncurl -X POST \"$API/api/v1/convert?dry_run=true\"   -H \"Authorization: Bearer $FACTURX_API_KEY\"   -F \"validation_target=france_2026\"   -F \"file=@./facture.pdf\"\n\ncurl -X POST \"$API/api/v1/convert\"   -H \"Authorization: Bearer $FACTURX_API_KEY\"   -H \"Idempotency-Key: facture-2026-france-001\"   -F \"validation_target=france_2026\"   -F \"file=@./facture.pdf\"   -F 'invoice_patch={\"payment\":{\"iban\":\"FR7630006000011234567890189\"}}'   -F 'seller_context={\"electronic_address\":{\"value\":\"99999123500014\",\"scheme_id\":\"0225\"},\"document_notes\":[{\"subject_code\":\"PMT\",\"content\":\"Indemnite forfaitaire de recouvrement de 40 EUR due en cas de retard de paiement\"},{\"subject_code\":\"PMD\",\"content\":\"Penalites de retard exigibles selon les conditions contractuelles\"},{\"subject_code\":\"AAB\",\"content\":\"Aucun escompte pour paiement anticipe\"}]}'   -F 'buyer_context={\"electronic_address\":{\"value\":\"98765432100011\",\"scheme_id\":\"0225\"}}'\n```\n\nRequest-context complements are stateless. They do not create or update a persisted FacturX profile. Saved issuer/client profile reuse is opt-in only (`profile_reuse=explicit`) and still rejects conflicts with visible PDF/XML values; when a document cannot be completed with supported request context or saved profile fields, send full `invoice_data` as the fallback structured ERP source.\n\n## Conversion Workflow\n\n1. **Scan Detection**: Determines if PDF is native text or scanned image\n2. **Data Extraction**: Extracts invoice data (text parsing or OCR)\n3. **XML Generation**: Creates candidate Factur-X XML, then validates whether it satisfies EN16931 and requested France 2026 / FNFE-MPE targets\n4. **PDF/A-3 Generation**: Embeds XML into PDF/A-3 format\n5. **Validation**: Validates the complete Factur-X document\n\n## Authentication\n\nRequires a public API key for server integrations:\n\n- `X-API-Key: <api_key>` header (recommended), or\n- `Authorization: Bearer <api_key>` header (alias for the same API key).\n\nDashboard session tokens and refresh cookies are not part of the public OpenAPI contract.\n\n## Idempotency\n\nUse `Idempotency-Key` header to ensure safe retries:\n- Same key + same payload = same response (cached)\n- Same key + different payload = 409 Conflict\n- Keys are scoped to the authenticated principal across both `POST /api/v1/convert`\n  and `POST /api/v1/repair`; cross-endpoint reuse returns 409 Conflict.\n- `validation_target`, `invoice_patch`, `seller_context` and `buyer_context` are included in the request identity.\n\n## Options\n\nControl conversion behavior via the `options` form field (JSON):\n```json\n{\n  \"output_profile\": \"EN16931\",\n  \"lang\": \"en\",\n  \"confidence_mode\": \"strict\",\n  \"seller_hint\": \"FR\",\n  \"buyer_hint\": \"DE\"\n}\n```\n\n### Confidence Mode\n- `strict` (default): Reject OCR results with confidence < 70%\n- `lenient`: Accept low confidence with warning in response\n\n## Response\n\nCompleted conversion and diagnostic results carry the canonical executable\nverdict in `validationReadiness`. Authentication, request and runtime failures\nuse the documented error response; inspect the HTTP status and error code\nbefore reading the result. For `validation_target=france_2026`,\n`validationReadiness.frCtc.dependsOn=[\"target_profile_valid\"]` and\n`targetProfileValid` tells whether the target profile gate actually passed.\n\n- `validationReadiness.frCtc.status=\"passed\"` — no fatal France 2026 blocker\n  remains for the executable checks against the effective pack. Inspect\n  `success` and the returned file to determine whether a final deliverable\n  was produced; passed France checks alone do not guarantee final generation\n  or delivery. Under the current France CTC pack,\n  BT-23, BT-34/BT-49 addresses, and BT-22 PMT/PMD/AAB are all pinned fatal, so\n  a \"passed\" status here means those specific occurrences were actually\n  resolved (or the rules do not apply to this document) — not that they were\n  waved through as advisory. If `advisories` is still non-empty, those remain\n  visible as reserves under whichever pack is effective (1.3.1 rollback: the\n  same rules at their own real, advisory severity). This is not PA acceptance\n  and not proof that every advisory is resolved.\n- `validationReadiness.frCtc.status=\"incomplete\"` — zero fatal blocker under\n  the effective pack, but at least one FNFE-MPE advisory remains (e.g. under\n  an explicit 1.3.1 rollback, where these six rules are genuinely still\n  advisory). The document is exchangeable but not fully conformant, so\n  `success=false` and the deliverable may still be returned as\n  produce-and-mark.\n- `blocked`, `not_run` or `not_evaluated` — `success=false`; the\n  `validationReadiness` layer explains the blockers, skipped runtime, missing\n  target profile proof, or Extended-CTC-FR non-executability.\n\nWhen a deliverable is returned, the PDF is base64-encoded in `pdf` for\nephemeral responses or exposed through `pdfUrl` when persistent storage is\nenabled. Use the `xml` field for the embedded XML.\n\n`success=true` is never emitted unless the requested target is passed in\n`validationReadiness`.\nValidation is technical. A France 2026 / FNFE-MPE pass does not prove PA lifecycle acceptance.\n\n## Quota Usage\n\n- Final `/convert` reserves 1 processed invoice before work starts.\n- If a deliverable is produced, the reserved invoice is charged\n  (`processedInvoicesCharged=1`).\n- If the requested target cannot produce a deliverable, the reserved quota is\n  refunded before the response reports `processedInvoicesCharged=0`.\n- OCR/cloud fallback budgets are enforced separately and do not change monthly quota.","operationId":"convert_invoice_api_v1_convert_post","parameters":[{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(en|fr)$"},{"type":"null"}],"description":"Response language (en or fr). Falls back to Accept-Language header.","title":"Lang"},"description":"Response language (en or fr). Falls back to Accept-Language header."},{"name":"dry_run","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Canonical non-billing preparation mode. Skips cloud OCR fallback and PDF/A-3 packaging. Legacy multipart dry_run and preview aliases are accepted, but every explicit value must match.","title":"Dry Run"},"description":"Canonical non-billing preparation mode. Skips cloud OCR fallback and PDF/A-3 packaging. Legacy multipart dry_run and preview aliases are accepted, but every explicit value must match."},{"name":"enrich","in":"query","required":false,"schema":{"type":"boolean","description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services.","default":true,"title":"Enrich"},"description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Idempotency key for safe retries (recommended for production use)","title":"Idempotency-Key"},"description":"Authenticated principal idempotency key shared by POST /api/v1/convert and POST /api/v1/repair; cross-endpoint reuse returns 409 Conflict."},{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Public API key header, recommended for server integrations."},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"},"description":"API key bearer alias: Authorization: Bearer <api_key>. Prefer X-API-Key for new server integrations."}],"requestBody":{"content":{"multipart/form-data":{"schema":{"allOf":[{"$ref":"#/components/schemas/Body_convert_invoice_api_v1_convert_post"}],"title":"Body"}}}},"responses":{"200":{"description":"Conversion or diagnostic result. Inspect success, validationReadiness, target and the returned deliverable; HTTP 200 alone does not prove successful conversion.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ConvertResponse"},{"$ref":"#/components/schemas/ConvertDryRunErrorEnvelopeResponse"}],"title":"Response 200 Convert Invoice Api V1 Convert Post"},"example":{"request_id":"req_01JEXAMPLE","success":true,"target":{"requested":"en16931","executed":"en16931","status":"verified","missing_inputs":[],"not_run_reason":null},"result":{"durationMs":2500,"convertedAt":"2026-01-04T12:00:00+00:00","targetProfile":"EN16931","conversionSuccessful":true,"xmlSize":4096,"xml":"PD94bWwgdmVyc2lvbj0iMS4wIj8+...","pdf":"JVBERi0xLjQK...","pdfSize":102400,"extraction":{"sourceType":"native_text","pageCount":1},"validation":{"valid":true,"profile":"EN16931"},"packagingPerformed":true,"processedInvoicesCharged":1,"remainingInvoices":99,"validationStatus":"valid","validationScopeLabel":"Factur-X EN16931 base","appliedValidationProfiles":["facturx_en16931_base"],"skippedValidationProfiles":[{"profile":"fr_ctc","reason":"feature_flag_disabled"}],"unsupportedValidationProfiles":[],"validationArtifacts":[{"id":"facturx-1.09.2-en16931-cii","family":"facturx","profile":"facturx_en16931_base","syntax":"cii","version":"1.09.2","sourceAuthority":"FNFE-MPE","sha256":"67f03050e3add4c83dc93de36e4501f6a11aae1ac790b3f9558feb0581019bcb","status":"available","executed":true}],"messageType":"invoice","legalDisclaimer":"Validation technique documentaire. Ne vaut pas acceptation par une Plateforme Agréée ni conformité fiscale finale.","validationReadiness":{"en16931":{"status":"passed","blockerCount":0,"advisoryCount":0,"blockers":[],"advisories":[],"evidence":"facturx_en16931_base_executed"},"facturxProfile":{"status":"not_evaluated","blockerCount":0,"advisoryCount":0,"blockers":[],"advisories":[],"reason":"source_profile_en16931"},"frCtc":{"status":"not_run","target":"not_applicable","blockerCount":0,"advisoryCount":0,"blockers":[],"advisories":[]},"paAcceptance":{"status":"not_submitted","blockerCount":0,"advisoryCount":0,"blockers":[],"advisories":[]},"packaging":{"status":"passed","blockerCount":0,"advisoryCount":0,"blockers":[],"advisories":[]}}}}},"application/pdf":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-FacturX-Source-Artifact-Id":{"description":"Opaque identity of the submitted source artifact.","schema":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$"}},"X-FacturX-Candidate-Artifact-Id":{"description":"Opaque identity of the generated dry-run candidate.","schema":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$"}},"X-FacturX-Candidate-Parent-Artifact-Id":{"description":"Submitted-source artifact identity that parents the candidate.","schema":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$"}},"X-FacturX-Output-Artifact-Id":{"description":"Opaque identity of the final generated output.","schema":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$"}},"X-FacturX-Output-Parent-Artifact-Id":{"description":"Dry-run candidate artifact identity that parents the output.","schema":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$"}},"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"202":{"description":"Conversion accepted for async processing","content":{"application/json":{"example":{"request_id":"req_01JEXAMPLE","success":false,"result":{"status":"processing","jobId":"2a65594d-7f60-431c-8e35-139a6eeb4cec"},"target":{"requested":"en16931","status":"not_run","missing_inputs":[],"not_run_reason":"async_processing_not_completed","executed":null}},"schema":{"$ref":"#/components/schemas/ConvertAsyncAcceptedResponse"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"400":{"description":"Invalid request","content":{"application/json":{"examples":{"empty_file":{"value":{"detail":{"error":"empty_file","message":"The uploaded file is empty."},"request_id":"req_01JEXAMPLE"}},"invalid_options":{"value":{"detail":{"error":"invalid_options_json","message":"Malformed JSON in options: ..."},"request_id":"req_01JEXAMPLE"}},"invoice_patch_with_invoice_data":{"value":{"detail":{"error":"invalid_invoice_patch","message":"invoice_patch cannot be combined with full invoice_data."},"request_id":"req_01JEXAMPLE"}},"conflicting_dry_run_parameters":{"value":{"detail":{"error":"conflicting_dry_run_parameters","message":"The dry_run query parameter, multipart dry_run field, and multipart preview alias must match when more than one is provided."},"request_id":"req_01JEXAMPLE"}}},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"Authentication required","content":{"application/json":{"example":{"detail":{"error":"authentication_required","message":"Authentication is required for the convert endpoint."},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"Quota mensuel de factures traitées atteint","content":{"application/json":{"example":{"detail":{"error":"quota_exceeded","message":"Quota mensuel de factures traitées atteint.","plan":"free","quota":100,"period_start":"2026-01-01T00:00:00Z"},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"Authenticated account cannot use the endpoint","content":{"application/json":{"example":{"detail":{"error":"user_suspended","message":"User account is suspended. Please contact support."},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"405":{"description":"Method not allowed; use POST for conversion","content":{"application/json":{"example":{"detail":{"error":"method_not_allowed","message":"This endpoint only accepts POST requests."},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"Idempotency conflict or inline context/document conflict","content":{"application/json":{"examples":{"conflict":{"value":{"detail":{"error":"idempotency_conflict","message":"Idempotency key was already used with a different request payload. Use a new Idempotency-Key for different requests.","retryable":false},"request_id":"req_01JEXAMPLE"}},"in_progress":{"value":{"detail":{"error":"idempotency_in_progress","message":"Operation with this idempotency key is currently in progress. Wait for the operation to complete before retrying.","processing_since":"2026-01-04T12:00:00Z","retryable":true},"request_id":"req_01JEXAMPLE"}},"inline_context_conflict":{"value":{"detail":{"error":"inline_context_conflict","message":"Inline context conflicts with document data.","resolution_policy":"document_value_wins","resolution_hint":"The document-visible value is authoritative. Remove or correct the inline context value, or correct the source document before retrying.","conflicts":[{"field":"seller.electronic_address.value","bt_code":"BT-34","document_value":"99999245600015","provided_value":"99999999900019","context_value":"99999999900019","resolution_policy":"document_value_wins","resolution_hint":"The document-visible value is authoritative. Remove or correct the inline context value, or correct the source document before retrying."}]},"request_id":"req_01JEXAMPLE"}},"inline_request_context_conflict":{"value":{"detail":{"error":"inline_context_conflict","message":"Inline context values conflict with each other.","resolution_policy":"request_context_conflict_requires_correction","resolution_hint":"Conflicting inline context values were provided for the same field. Submit one value, or make the request-context values match before retrying.","conflicts":[{"field":"document_notes.PMT","bt_code":"BT-22","existing_request_path":"seller_context.document_notes[0]","existing_request_value":"Paiement par virement","provided_request_path":"buyer_context.document_notes[0]","provided_value":"Paiement par carte","context_value":"Paiement par carte","resolution_policy":"request_context_conflict_requires_correction","resolution_hint":"Conflicting inline context values were provided for the same field. Submit one value, or make the request-context values match before retrying."}]},"request_id":"req_01JEXAMPLE"}},"inline_mixed_context_conflict":{"value":{"detail":{"error":"inline_context_conflict","message":"Inline context contains multiple conflicts that require review.","resolution_policy":"resolve_each_conflict","resolution_hint":"Resolve each conflict according to its per-conflict resolution_hint before retrying.","conflicts":[{"field":"seller.electronic_address.value","bt_code":"BT-34","document_value":"99999245600015","provided_value":"99999999900019","context_value":"99999999900019","resolution_policy":"document_value_wins","resolution_hint":"The document-visible value is authoritative. Remove or correct the inline context value, or correct the source document before retrying."},{"field":"document_notes.PMT","bt_code":"BT-22","existing_request_path":"seller_context.document_notes[0]","existing_request_value":"Paiement par virement","provided_request_path":"buyer_context.document_notes[0]","provided_value":"Paiement par carte","context_value":"Paiement par carte","resolution_policy":"request_context_conflict_requires_correction","resolution_hint":"Conflicting inline context values were provided for the same field. Submit one value, or make the request-context values match before retrying."}]},"request_id":"req_01JEXAMPLE"}}},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"413":{"description":"File too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"415":{"description":"Unsupported media type (non-PDF file)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"422":{"description":"Unprocessable entity","content":{"application/json":{"examples":{"unextractable":{"value":{"detail":{"error":"unextractable_pdf","message":"Unable to extract invoice data from PDF. The PDF may be corrupt, password-protected, or not contain invoice content."},"request_id":"req_01JEXAMPLE"}},"low_confidence":{"value":{"detail":{"error":"ocr_confidence_too_low","message":"OCR confidence (45.2%) is below threshold (70%). Use confidence_mode='lenient' to accept low-confidence results.","confidence":45.2,"threshold":70.0},"request_id":"req_01JEXAMPLE"}},"insufficient_data":{"value":{"detail":{"error":"insufficient_data","message":"Required invoice fields are missing.","missing_fields":["seller.name","invoice_number"]},"request_id":"req_01JEXAMPLE"}},"invalid_format":{"value":{"detail":{"error":"invalid_data_format","message":"Invoice data contains invalid format.","field":"issue_date"},"request_id":"req_01JEXAMPLE"}},"invalid_invoice_patch":{"summary":"Invalid inline invoice patch","value":{"detail":{"error":"invalid_invoice_patch","message":"invoice_patch is invalid, for example an impossible date."},"request_id":"req_01JEXAMPLE"}},"patch_without_reference":{"summary":"BT-26 provided without an effective prior invoice reference","value":{"detail":{"error":"insufficient_data","message":"invoice_patch.preceding_invoice.issue_date requires a matching effective preceding invoice reference."},"request_id":"req_01JEXAMPLE"}},"validation_failed":{"value":{"detail":{"error":"pdf_validation_failed","message":"Generated PDF failed compliance validation."},"request_id":"req_01JEXAMPLE"}},"validation_profile_unavailable":{"summary":"Explicit validation_profile cannot be applied","value":{"detail":{"error":"validation_profile_unavailable","message":"The requested validation profile could not run for this document in this runtime. Check the requested profile and supported profile/syntax combinations. Request EN16931-only validation only if it meets your intended scope; changing the target does not verify the original target."},"request_id":"req_01JEXAMPLE"}}},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"example":{"detail":{"error":"rate_limit_exceeded","message":"Too many requests. Please try again later.","retry_after_seconds":30},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"Unexpected conversion failure","content":{"application/json":{"example":{"detail":{"error":"internal_server_error","message":"The conversion could not be completed.","retryable":false},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"502":{"description":"Gateway could not reach the conversion service","content":{"application/json":{"example":{"detail":{"error":"backend_error","message":"Failed to connect to backend service.","retryable":true},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Service unavailable (OCR or PDF generation)","content":{"application/json":{"examples":{"ocr_service_unavailable":{"value":{"detail":{"error":"ocr_service_unavailable","message":"OCR service is temporarily unavailable. Please try again later.","retry_after_seconds":60,"retryable":true},"request_id":"req_01JEXAMPLE"}},"ocr_quota_exhausted":{"value":{"detail":{"error":"ocr_quota_exhausted","message":"OCR fallback is temporarily unavailable on this deployment. Please try again later.","retry_after_seconds":300,"retryable":true},"request_id":"req_01JEXAMPLE"}}},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"504":{"description":"Timeout (OCR or PDF generation)","content":{"application/json":{"example":{"detail":{"error":"ocr_timeout","message":"OCR processing timed out. The document may be too large or complex."},"request_id":"req_01JEXAMPLE"},"schema":{"$ref":"#/components/schemas/ApiErrorEnvelope"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}},"x-facturx-convert-error-registry":{"schema_version":1,"source":"app.application.dto.convert_error_registry.CONVERT_ERROR_REGISTRY","entries":[{"code":"authentication_required","statuses":[401],"strategies":["no_retry_fix_request"]},{"code":"missing_api_key","statuses":[401],"strategies":["no_retry_fix_request"]},{"code":"invalid_api_key","statuses":[401],"strategies":["no_retry_fix_request"]},{"code":"key_revoked","statuses":[401],"strategies":["no_retry_fix_request"]},{"code":"key_not_linked","statuses":[401],"strategies":["no_retry_fix_request"]},{"code":"user_suspended","statuses":[403],"strategies":["contact_support_with_request_id"]},{"code":"user_not_found","statuses":[403,404],"strategies":["contact_support_with_request_id"]},{"code":"method_not_allowed","statuses":[405],"strategies":["no_retry_fix_request"]},{"code":"empty_file","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"bad_request","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"request_failed","statuses":[400,500],"strategies":["contact_support_with_request_id"]},{"code":"file_required","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"file_required_for_pdf_output","statuses":[400],"strategies":["no_retry_fix_request","switch_to_xml_cii_possible"]},{"code":"invalid_options_json","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"invalid_options","statuses":[400],"strategies":["no_retry_fix_request","switch_to_xml_cii_possible"]},{"code":"invalid_idempotency_key","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"invalid_invoice_patch","statuses":[400,422],"strategies":["no_retry_fix_request"]},{"code":"invalid_invoice_data","statuses":[400,422],"strategies":["no_retry_fix_request"]},{"code":"invalid_invoice_data_source_conflict","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"invalid_seller_context","statuses":[400,422],"strategies":["no_retry_fix_request"]},{"code":"invalid_seller_profile_inline","statuses":[400,422],"strategies":["no_retry_fix_request"]},{"code":"invalid_buyer_context","statuses":[400,422],"strategies":["no_retry_fix_request"]},{"code":"invalid_buyer_profile_inline","statuses":[400,422],"strategies":["no_retry_fix_request"]},{"code":"conflicting_dry_run_parameters","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"source_profile_requires_generated_candidate","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"inline_context_conflict","statuses":[409],"strategies":["no_retry_fix_request"]},{"code":"conflict","statuses":[409],"strategies":["no_retry_fix_request"]},{"code":"idempotency_conflict","statuses":[409],"strategies":["no_retry_fix_request"]},{"code":"idempotency_in_progress","statuses":[409],"strategies":["retry_same_key","poll_job_status"]},{"code":"idempotency_response_unavailable","statuses":[409,503],"strategies":["no_retry_fix_request","retry_same_key"]},{"code":"file_too_large","statuses":[413],"strategies":["no_retry_fix_request"]},{"code":"request_body_too_large","statuses":[413],"strategies":["no_retry_fix_request"]},{"code":"max_pages_exceeded","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"unsupported_media_type","statuses":[415],"strategies":["no_retry_fix_request"]},{"code":"unsupported_content_type","statuses":[415],"strategies":["no_retry_fix_request"]},{"code":"insufficient_data","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"unextractable_pdf","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"ocr_confidence_too_low","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"invalid_data_format","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"unsupported_field_value","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"multi_payment_means_unsupported","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"unsupported_output_profile_for_invoice_data","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"unsupported_output_profile_for_ubl_source","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"ubl_pdf_carrier_required","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"ubl_source_mapping_unsupported","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"ubl_source_mapping_incomplete","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"ubl_source_not_valid_en16931","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"ubl_source_validation_timeout","statuses":[504],"strategies":["retry_same_key"]},{"code":"pdf_validation_failed","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"validation_profile_unavailable","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"profile_unknown","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"request_validation_error","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"material_invariant_refused","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"target_validation_failed","statuses":[200],"strategies":["no_retry_fix_request","quota_refunded"]},{"code":"quota_exceeded","statuses":[402],"strategies":["no_retry_fix_request"]},{"code":"convert_jobs_budget_exhausted","statuses":[402],"strategies":["no_retry_fix_request"]},{"code":"rate_limit_exceeded","statuses":[429],"strategies":["retry_after_required","retry_same_key"]},{"code":"requested_output_unavailable","statuses":[503],"strategies":["retry_same_key","switch_to_xml_cii_possible","quota_refunded"]},{"code":"ocr_service_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"ocr_quota_exhausted","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"async_queue_unavailable","statuses":[503],"strategies":["retry_same_key"]},{"code":"async_enqueue_status_unknown","statuses":[503],"strategies":["retry_same_key","poll_job_status"]},{"code":"pdf_generation_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"PDFA_VERIFICATION_UNAVAILABLE","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"validation_service_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"backend_unavailable","statuses":[503],"strategies":["retry_same_key"]},{"code":"billable_operation_store_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"idempotency_store_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"database_not_configured","statuses":[503],"strategies":["contact_support_with_request_id"]},{"code":"database_unavailable","statuses":[503],"strategies":["retry_same_key"]},{"code":"quota_constraint_error","statuses":[503],"strategies":["contact_support_with_request_id"]},{"code":"service_unavailable","statuses":[503],"strategies":["retry_same_key"]},{"code":"service_temporarily_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"storage_unavailable","statuses":[503],"strategies":["retry_same_key"]},{"code":"artifact_url_unavailable","statuses":[503],"strategies":["retry_same_key"]},{"code":"pdf_generation_timeout","statuses":[504],"strategies":["retry_same_key","switch_to_xml_cii_possible"]},{"code":"conversion_timeout","statuses":[504],"strategies":["retry_same_key"]},{"code":"ocr_timeout","statuses":[504],"strategies":["retry_same_key","no_retry_fix_request"]},{"code":"backend_timeout","statuses":[504],"strategies":["retry_same_key"]},{"code":"upstream_timeout","statuses":[504],"strategies":["retry_same_key"]},{"code":"quota_refund_unconfirmed","statuses":[503],"strategies":["contact_support_with_request_id"]},{"code":"generation_refused","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"monthly_quota_reservation_unavailable","statuses":[503],"strategies":["retry_after_required","retry_same_key"]},{"code":"monthly_quota_reservation_release_unavailable","statuses":[503],"strategies":["retry_after_required","contact_support_with_request_id"]},{"code":"job_not_found","statuses":[404],"strategies":["no_retry_fix_request"]},{"code":"artifact_not_found","statuses":[404],"strategies":["no_retry_fix_request"]},{"code":"artifact_unavailable","statuses":[409],"strategies":["poll_job_status"]},{"code":"invalid_request","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"backend_error","statuses":[502],"strategies":["retry_same_key"]},{"code":"database_error","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"internal_error","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"idempotency_invariant_failed","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"billable_receipt_not_chargeable","statuses":[409],"strategies":["no_retry_fix_request"]},{"code":"internal_validation_orchestration_error","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"causal_artifact_contract_violation","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"execution_receipt_contract_violation","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"final_control_failed","statuses":[422],"strategies":["no_retry_fix_request","quota_refunded"]},{"code":"product_truth_invariant_violation","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"public_scan_product_truth_processing_failed","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"OUTPUT_NOT_PDFA3_CONFORMANT","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"GENERATION_DECISION_BACKEND_UNREADABLE","statuses":[409,503],"strategies":["no_retry_fix_request","contact_support_with_request_id"]},{"code":"xml_only_packaging_refused","statuses":[409],"strategies":["no_retry_fix_request","switch_to_xml_cii_possible"]},{"code":"PRODUCT_TRUTH_POST_ATTACH_NORMALIZE_FAILED","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"internal_server_error","statuses":[500],"strategies":["contact_support_with_request_id"]},{"code":"unsupported_output_profile_for_cii_source","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"xml_security_error","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"cii_source_unsupported","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"cii_source_profile_header_only","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"cii_xml_source_overlay_unsupported","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"cii_source_validation_timeout","statuses":[504],"strategies":["retry_same_key"]},{"code":"cii_source_not_valid","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"cii_source_mapping_incomplete","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"invalid_preservation_verification_command","statuses":[400],"strategies":["no_retry_fix_request"]},{"code":"preservation_verification_grant_required","statuses":[403],"strategies":["no_retry_fix_request"]},{"code":"preservation_verification_unavailable","statuses":[409,503],"strategies":["no_retry_fix_request"]},{"code":"preservation_verification_timeout","statuses":[504],"strategies":["no_retry_fix_request"]},{"code":"preservation_verification_failed","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"invoice_data_carrier_missing_glyph","statuses":[422],"strategies":["no_retry_fix_request"]},{"code":"generation_input_invalid","statuses":[422],"strategies":["no_retry_fix_request"]}]},"security":[{"PublicApiKeyHeader":[]},{"PublicApiKeyBearer":[]}]}},"/api/v1/extract":{"post":{"tags":["extract"],"summary":"Extract Factur-X XML from PDF","description":"Extracts the embedded Factur-X XML from a PDF file. This API endpoint is the public integration scan surface (`/api/v1/extract`); the Web `/scan` flow consumes scan-compatible Product Truth payloads built from the same document evidence.\n\n## Features\n\n1. **XML Extraction**: Extracts the embedded XML attachment from Factur-X PDFs\n2. **Profile Detection**: Automatically detects the Factur-X profile (MINIMUM, BASIC_WL, BASIC, EN16931, EXTENDED)\n3. **Optional Validation**: Validates the extracted XML against XSD/Schematron rules\n4. **Truth boundaries**: distinguishes EN16931 base validation, France CTC / FNFE-MPE readiness for the executed pack, and PA lifecycle acceptance. A scan or extract response is technical evidence only; PA acceptance requires a real external PA lifecycle event.\n\n## Product Truth relation\n\nThe bare `/api/v1/extract` response returns extraction evidence (`xml`, `xmlSize`, `profile`, optional `validation`) and does not emit Product Truth fields directly. When the Web scan/dry-run product layer wraps this evidence, clients must read Product Truth `requirements`, `fieldProvenance`, `validationReadiness`, and `conversionInputRecipe` instead of treating warnings as missing ERP data. Field provenance uses user-level sources (`document`, `profile`, `request_context`, `conflict`) and may expose parser details such as XML/PDF extraction only as technical metadata. Bare extract/scan does not load saved profiles itself; when `conversionInputRecipe` marks a field `saved-profile-supported`, call `/convert` with `profile_reuse=explicit` and tenant-scoped profile selectors. Default or heuristic profile lookup remains unsupported.\n\n## Authentication\n\nRequires a public API key for server integrations:\n\n- `X-API-Key: <api_key>` header (recommended), or\n- `Authorization: Bearer <api_key>` header (alias for the same API key).\n\nDashboard session tokens and refresh cookies are not part of the public OpenAPI contract.\n\n## Query Parameters\n\n- `validate=true`: Run full PDF validation in the same invoice-treated call\n- `lang=en|fr`: Language for response messages\n\n## Response\n\nReturns extraction evidence with metadata:\n- `xml`: Embedded XML, **base64-encoded** for safe JSON transport (decode client-side; not plaintext)\n- `xmlSize`: Size of the decoded XML in bytes\n- `json`: Canonical invoice_data parsed from the embedded XML when parsing succeeds\n- `profile`: Detected Factur-X profile\n- `durationMs`: Extraction time in milliseconds\n- `enrichment`: Optional Sirene/company enrichment when enrich ran\n- `validation`: Optional validation report (if validate=true)\n\n## Quota Usage\n\n- 1 processed invoice per API call, including with `validate=true`","operationId":"extract_facturx_api_v1_extract_post","parameters":[{"name":"validate","in":"query","required":false,"schema":{"type":"boolean","description":"Run validation after extraction in the same processed-invoice call","default":false,"title":"Validate"},"description":"Run validation after extraction in the same processed-invoice call"},{"name":"enrich","in":"query","required":false,"schema":{"type":"boolean","description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services.","default":true,"title":"Enrich"},"description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services."},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(en|fr)$"},{"type":"null"}],"description":"Response language (en or fr). Falls back to Accept-Language header.","title":"Lang"},"description":"Response language (en or fr). Falls back to Accept-Language header."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Idempotency key for replay-safe billing","title":"Idempotency-Key"},"description":"Idempotency key for replay-safe billing"},{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Public API key header, recommended for server integrations."},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"},"description":"API key bearer alias: Authorization: Bearer <api_key>. Prefer X-API-Key for new server integrations."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_extract_facturx_api_v1_extract_post"}}}},"responses":{"200":{"description":"XML extracted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractResponse"},"example":{"xml":"PD94bWwgdmVyc2lvbj0iMS4wIj8+...","xmlSize":2048,"json":{"invoice_number":"F20260029","currency":"EUR"},"profile":"EN16931","filename":"invoice.pdf","extractedAt":"2024-01-15T12:00:00Z","durationMs":42}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"400":{"description":"Invalid request","content":{"application/json":{"example":{"detail":"Empty file"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"Authentication required","content":{"application/json":{"example":{"error":"authentication_required","message":"Authentication is required for the extract endpoint."}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"Quota mensuel de factures traitées atteint","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"413":{"description":"File too large","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"415":{"description":"Unsupported media type (non-PDF file)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"422":{"description":"PDF without Factur-X XML","content":{"application/json":{"example":{"error":"unextractable_pdf","message":"PDF does not contain embedded Factur-X XML attachment."}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"example":{"error":"rate_limit_exceeded","message":"Too many requests. Please try again later.","retry_after_seconds":30}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Service unavailable","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}},"security":[{"PublicApiKeyHeader":[]},{"PublicApiKeyBearer":[]}]}},"/api/v1/integration-contract":{"get":{"tags":["integration-contract"],"summary":"Public ERP integration contract (source-of-truth, read-only)","description":"Machine-readable description of the public /convert invoice_data schema: fields, EN16931/France-2026 rule references (grounded against the engine's compiled Schematron), CII mapping, readiness levels and golden examples. Generated from the engine source of truth; contains no customer data.","operationId":"get_integration_contract_api_v1_integration_contract_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Integration contract artifact unavailable","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}}},"head":{"tags":["integration-contract"],"summary":"Public ERP integration contract (source-of-truth, read-only)","description":"Machine-readable description of the public /convert invoice_data schema: fields, EN16931/France-2026 rule references (grounded against the engine's compiled Schematron), CII mapping, readiness levels and golden examples. Generated from the engine source of truth; contains no customer data.","operationId":"head_integration_contract","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Integration contract artifact unavailable","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}}}},"/api/v1/repair":{"post":{"tags":["repair"],"summary":"Repair Factur-X XML","description":"Repairs a standalone Factur-X CII XML file with the deterministic format corrections listed below. It never invents missing business data, recalculates VAT or business totals, creates an empty `ram:ApplicableHeaderTradeDelivery` structural wrapper, or repairs an IBAN.\n\n## Three-Phase Workflow\n\n1. **Validate BEFORE**: Capture the initial validation state\n2. **Apply Repairs**: Apply only deterministic, constraint-authorized repair rules\n3. **Validate AFTER**: Report the target-scoped validation outcome after repair\n\n## Repair Rules Applied\n\n- **R001**: Date format correction (for example YYYY-MM-DD to YYYYMMDD)\n- **R002**: Decimal separator normalization on the listed monetary elements only; it is disabled by default and requires do_not_modify_amounts=false\n- **R005**: CII namespace prefix and URI normalization\n- **R006**: schemeID=\"VA\" only for a supported VAT-registration value; ambiguous GlobalID values produce UNDETERMINED_SCHEME_ID without mutation\n- **R007**: Casing normalization for an existing currency code (for example eur to EUR); a missing business currency is not invented\n- **R009**: Supported UN/ECE quantity unit normalization (for example For to C62)\n\n## Authentication\n\nRequires a public API key for server integrations:\n\n- `X-API-Key: <api_key>` header (recommended), or\n- `Authorization: Bearer <api_key>` header (alias for the same API key).\n\nDashboard session tokens and refresh cookies are not part of the public OpenAPI contract.\n\n## Idempotency\n\nUse `Idempotency-Key` for safe retries:\n- Same key + same payload = same response (cached)\n- Same key + different payload = 409 Conflict\n- Keys are scoped to the authenticated principal across both `POST /api/v1/convert`\n  and `POST /api/v1/repair`; cross-endpoint reuse returns 409 Conflict.\n\n## Constraints\n\nThe optional `constraints` multipart field controls the repair budget and material-value protections. The public first-run request leaves it disabled. In particular, `do_not_modify_amounts` defaults to true. R002 only inspects the ten monetary element paths published in `x-facturx-repair-contract`; it does not rewrite every `xs:decimal` value.\n\n## Response\n\nReturns the repaired XML with before/after validation reports and a diff summary. A warning such as `UNDETERMINED_SCHEME_ID` is diagnostic evidence, not a mutation.","operationId":"repair_facturx_xml_api_v1_repair_post","parameters":[{"name":"target_profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(MINIMUM|BASIC_WL|BASIC|EN16931|EXTENDED)$"},{"type":"null"}],"description":"Target Factur-X profile for repair. If not specified, auto-detected from XML.","title":"Target Profile"},"description":"Target Factur-X profile for repair. If not specified, auto-detected from XML."},{"name":"enrich","in":"query","required":false,"schema":{"type":"boolean","description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services.","default":true,"title":"Enrich"},"description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services."},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(en|fr)$"},{"type":"null"}],"description":"Response language (en or fr). Falls back to Accept-Language header.","title":"Lang"},"description":"Response language (en or fr). Falls back to Accept-Language header."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Authenticated-principal idempotency key shared by POST /api/v1/convert and POST /api/v1/repair; cross-endpoint reuse returns 409 Conflict","title":"Idempotency-Key"},"description":"Authenticated principal idempotency key shared by POST /api/v1/convert and POST /api/v1/repair; cross-endpoint reuse returns 409 Conflict."},{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Public API key header, recommended for server integrations."},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"},"description":"API key bearer alias: Authorization: Bearer <api_key>. Prefer X-API-Key for new server integrations."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_repair_facturx_xml_api_v1_repair_post"}}}},"responses":{"200":{"description":"Repair result, including unchanged or still-invalid XML. Inspect repairApplied, repairSuccessful, targetVerified and validation_after.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairResponse"},"example":{"durationMs":124,"repaired_xml":"PD94bWwgdmVyc2lvbj0iMS4wIj8+...","diff_summary":[{"code":"format_corrected","path":"/rsm:CrossIndustryInvoice/.../ram:IssueDateTime","message":"Corrected date format from '2024-01-15' to '20240115'","beforeValue":"2024-01-15","afterValue":"20240115","ruleReference":"R001","changeCategory":"correction"}],"changesCount":1,"wasModified":true,"repairApplied":true,"targetVerified":true,"validation_before":{"valid":false,"target":{"requested":"en16931","executed":"en16931","status":"failed","missing_inputs":[],"not_run_reason":null},"summary":{"errorCount":2,"warningCount":0}},"target":{"requested":"en16931","executed":"en16931","status":"verified","missing_inputs":[],"not_run_reason":null},"repairSuccessful":true,"validation_after":{"valid":true,"target":{"requested":"en16931","executed":"en16931","status":"verified","missing_inputs":[],"not_run_reason":null},"summary":{"errorCount":0,"warningCount":0}}}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"400":{"description":"Invalid request","content":{"application/json":{"examples":{"empty_file":{"value":{"detail":"Empty file"}},"invalid_constraints":{"value":{"error":"invalid_constraints_json","message":"Malformed JSON in constraints: ..."}}}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"Quota mensuel de factures traitées atteint","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"Idempotency conflict, including authenticated-principal cross-endpoint reuse between POST /api/v1/convert and POST /api/v1/repair","content":{"application/json":{"example":{"error":"idempotency_conflict","message":"Idempotency key was already used by this authenticated principal for a different request or endpoint. Use a new Idempotency-Key."}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"413":{"description":"File too large","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"415":{"description":"Unsupported media type (non-XML file)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"422":{"description":"Unprocessable entity","content":{"application/json":{"examples":{"xml_parse_error":{"value":{"error":"xml_parse_error","message":"XML syntax error: ..."}},"xml_security_error":{"value":{"error":"xml_security_error","message":"XML security violation: potential XXE attack detected"}},"constraint_exceeded":{"value":{"error":"repair_constraint_exceeded","message":"Repair would exceed max_changes_allowed limit"}}}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"example":{"error":"rate_limit_exceeded","message":"Too many requests. Please try again later.","retry_after_seconds":30}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Service unavailable","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}},"x-facturx-repair-contract":{"schemaVersion":1,"defaultConstraints":{"do_not_modify_amounts":true},"rules":[{"code":"R001","description":"Date format correction (for example YYYY-MM-DD to YYYYMMDD)"},{"code":"R002","description":"Decimal separator normalization on the listed monetary elements only; it is disabled by default and requires do_not_modify_amounts=false","enabledWhen":{"constraints.do_not_modify_amounts":false},"supportedElementXPaths":[".//ram:ChargeAmount",".//ram:TaxBasisTotalAmount",".//ram:TaxTotalAmount",".//ram:GrandTotalAmount",".//ram:DuePayableAmount",".//ram:LineTotalAmount",".//ram:CalculatedAmount",".//ram:BasisAmount",".//ram:AllowanceAmount",".//ram:ActualAmount"]},{"code":"R005","description":"CII namespace prefix and URI normalization"},{"code":"R006","description":"schemeID=\"VA\" only for a supported VAT-registration value; ambiguous GlobalID values produce UNDETERMINED_SCHEME_ID without mutation","mutations":[{"xpath":".//ram:SpecifiedTaxRegistration/ram:ID","schemeID":"VA","condition":"VAT_SCHEME_PATTERN"}],"diagnosticsWithoutMutation":[{"xpath":".//ram:GlobalID","code":"UNDETERMINED_SCHEME_ID"}]},{"code":"R007","description":"Casing normalization for an existing currency code (for example eur to EUR); a missing business currency is not invented"},{"code":"R009","description":"Supported UN/ECE quantity unit normalization (for example For to C62)"}]},"security":[{"PublicApiKeyHeader":[]},{"PublicApiKeyBearer":[]}]}},"/api/v1/trial/integration/start":{"post":{"tags":["trial"],"summary":"Retired Integration trial endpoint","description":"The former Integration trial is retired. Use the canonical Sandbox API-key flow instead.","operationId":"trial_integration_start_api_v1_trial_integration_start_post","responses":{"410":{"description":"The legacy Integration trial is retired.","content":{"application/json":{"schema":{}},"application/problem+json":{"schema":{"properties":{"type":{"type":"string","title":"Type","default":"/problems/legacy-trial-retired"},"title":{"type":"string","title":"Title","default":"Legacy Integration trial retired"},"status":{"type":"integer","title":"Status","default":410},"detail":{"type":"string","title":"Detail","default":"The Integration trial is retired. Use the canonical Sandbox API-key flow instead."},"next":{"type":"string","format":"uri","title":"Next","description":"Absolute frontend URL for the canonical Sandbox action.","example":"https://facturxapi.com/api-key"}},"type":"object","required":["next"],"title":"LegacyTrialRetiredProblem","description":"RFC 7807 response for the retired public Integration trial route."}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}}}},"/api/v1/validate":{"post":{"tags":["validation"],"summary":"Valider une facture Factur-X","description":"Valide une facture électronique au format **Factur-X** (PDF ou XML).\n\n## Authentification\n\nCet endpoint public utilise une clé API pour les intégrations serveur :\n\n- `X-API-Key: <key>` (recommandé), ou\n- `Authorization: Bearer <api_key>` (alias de la même clé API).\n\nLes jetons dashboard et cookies de session ne font pas partie du contrat public OpenAPI.\n\n## 📥 Formats supportés\n\n- **PDF Factur-X** : PDF avec XML embarqué conforme EN16931\n- **XML standalone** : Fichier XML Factur-X seul\n\n## ✅ Validations effectuées\n\n1. **Validation PDF/A-3** : Vérifie la conformité PDF/A-3 (si PDF)\n2. **Validation structure Factur-X** : Vérifie les pièces jointes et métadonnées XMP (si PDF)\n3. **Validation XSD** : Vérifie la structure XML contre le schéma XSD\n4. **Validation Schematron EN16931** : Vérifie les règles métier européennes\n5. **France 2026 / FNFE-MPE** : si demandé par `validation_target=france_2026`, par les contrôles legacy `validation_profile=fr_ctc` / `validation_profile=auto&jurisdiction=FR`, ou par preuve pays document (`CountryID=FR` vendeur/client avec `jurisdiction=UNKNOWN`), applique la cible France CTC quand le runtime est disponible. La version des artefacts utilisés est indiquée dans `validationArtifacts` et `validationReadiness.frCtc`. `/api/v1/meta` distingue la version sélectionnée du runtime chargé ; un rollback explicite utilise les règles de sa propre version.\n\nCette validation est technique. Elle ne soumet pas le document à une Plateforme Agréée et ne vaut pas acceptation PA.\n\n## Product Truth et provenance\n\n`/validate` retourne la vérité de validation technique: `issues`, `stages`, `validationArtifacts`, `validationTarget` et `validationReadiness` séparent la cible demandée, le socle EN16931, la cible France CTC / FNFE-MPE du pack exécuté et l'état `paAcceptance`. Les champs lifecycle `submittedSourceReadiness`, `candidateValidationReadiness` et `finalGeneratedValidation` sont nommés dans le contrat pour garder distincts le fichier soumis, un candidat généré et un livrable final; ils peuvent être absents/null sur une validation source pure. Le `validationStatus` legacy est ramené à `error` lorsqu'une cible demandée n'a pas été évaluée, afin qu'un client ne transforme pas une base EN16931 verte en promesse France 2026. Il ne produit pas de `conversionInputRecipe` actionnable pour réparer une facture; les exigences Product Truth, la `fieldProvenance`, les compléments inline et les gaps de réutilisation de profils persistants sont exposés par les surfaces scan/dry-run `/convert`. Si un champ de classification public (`status`, `internalCategory`, `uiBucket`) est présent sur une issue, il doit être explicite et non nul.\n\n## 🎯 Cibles de validation\n\n- `validation_target=en16931` : socle Factur-X / EN16931 uniquement.\n- `validation_target=france_2026` : EN16931 + exigences France 2026 / FNFE-MPE disponibles. Cette cible ne vaut pas soumission ni acceptation Plateforme Agréée.\n- `validation_profile=facturx_en16931_base` : ancien contrôle équivalent à EN16931 uniquement.\n- `validation_profile=auto&jurisdiction=FR` : ancien contrôle qui cible France 2026 quand les artefacts/runtime France CTC sont disponibles.\n- `validation_profile=auto&jurisdiction=UNKNOWN` : cible France 2026 uniquement si les pays vendeur/client extraits du XML prouvent `FR`; les pays inconnus/non-FR restent EN16931 only avec raison explicite.\n- `validation_profile=auto&jurisdiction=EU` avec preuve document FR : expose un conflit `validationTarget` sans exécuter France CTC ni afficher de blockers France CTC.\n- `validation_profile=auto&jurisdiction=FR` avec preuve document non-FR : exécute la cible demandée mais expose un conflit `validationTarget` request/document.\n- Un runtime France CTC indisponible en mode `auto` est rendu comme `validationTarget.frCtc.target=unavailable` ou `runtime_error`, pas comme un blocker document.\n- `validation_profile=fr_ctc` : demande explicite France CTC; retourne 422 si la cible n'est pas exécutable.\n- `legacy=true` : conserve l'ancien format court de réponse; le format par défaut reste le rapport unifié.\n\nLes erreurs de résolution de profil sont classées avant ou remboursées par le wrapper quota, afin de ne pas facturer un échec runtime déterministe de cible non exécutable.\n\n## 📤 Réponses possibles\n\n### Succès (200 OK) - Format unifié (par défaut)\n```json\n{\n  \"valid\": true,\n  \"validatedAt\": \"2025-12-27T12:23:51.676602+00:00\",\n  \"filename\": \"invoice.xml\",\n  \"profile\": \"EN16931\",\n  \"durationMs\": 124,\n  \"summary\": { \"errorCount\": 0, \"warningCount\": 0 },\n  \"issues\": [],\n  \"stages\": {\n    \"pdfa\": { \"passed\": true, \"skipped\": true, \"skip_reason\": \"XML file - PDF/A validation not applicable\", \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] },\n    \"facturx_pdf\": { \"passed\": true, \"skipped\": true, \"skip_reason\": \"XML file - PDF checks not applicable\", \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] },\n    \"xsd\": { \"passed\": true, \"skipped\": false, \"skip_reason\": null, \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] },\n    \"schematron\": { \"passed\": true, \"skipped\": false, \"skip_reason\": null, \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] }\n  },\n  \"errors\": [],\n  \"warnings\": []\n}\n```\n\n### Succès (200 OK) - Format legacy (?legacy=true)\n```json\n{\n  \"valid\": true,\n  \"errors\": [],\n  \"warnings\": [],\n  \"profile\": \"EN16931\",\n  \"message\": \"Validation completed\"\n}\n```\n\n### Validation échouée (200 OK avec valid=false)\n```json\n{\n  \"valid\": false,\n  \"validatedAt\": \"2025-12-27T12:23:51.676602+00:00\",\n  \"filename\": \"invoice.xml\",\n  \"profile\": \"EN16931\",\n  \"durationMs\": 124,\n  \"summary\": { \"errorCount\": 1, \"warningCount\": 0 },\n  \"issues\": [\n    {\n      \"code\": \"XSD_VALIDATION_ERROR\",\n      \"severity\": \"error\",\n      \"stage\": \"xsd\",\n      \"message\": \"Missing required element: InvoiceNumber\",\n      \"line\": 42,\n      \"expected\": \"InvoiceNumber\",\n      \"actual\": null,\n      \"location\": \"line 42\",\n      \"ruleId\": null,\n      \"xpath\": \"/Invoice/ID\"\n    }\n  ],\n  \"stages\": {\n    \"pdfa\": { \"passed\": true, \"skipped\": true, \"skip_reason\": \"XML file - PDF/A validation not applicable\", \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] },\n    \"facturx_pdf\": { \"passed\": true, \"skipped\": true, \"skip_reason\": \"XML file - PDF checks not applicable\", \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] },\n    \"xsd\": { \"passed\": false, \"skipped\": false, \"skip_reason\": null, \"error_count\": 1, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] },\n    \"schematron\": { \"passed\": true, \"skipped\": false, \"skip_reason\": null, \"error_count\": 0, \"warning_count\": 0, \"info_count\": 0, \"issues\": [] }\n  },\n  \"errors\": [],\n  \"warnings\": []\n}\n```\n\n### Erreur fichier vide (400 Bad Request)\n```json\n{\n  \"detail\": \"Empty file\"\n}\n```\n\n## 🌍 Internationalisation\n\nUtilisez le header **Accept-Language** pour obtenir les messages en français:\n- `Accept-Language: en` (par défaut)\n- `Accept-Language: fr`\n\n## 💾 Stockage\n\nPar défaut (`KEEP_UPLOADS=false` et `FILE_RETENTION_SECONDS=0`), le fichier\nest traité pendant la requête et aucune copie n'est écrite dans le stockage\nd'artefacts. Si une rétention explicite est configurée, le fichier est conservé\nsur R2/stockage local pendant la durée configurée; si `KEEP_UPLOADS=true`, il\nest conservé jusqu'à purge administrative.","operationId":"validate_facturx_api_v1_validate_post","parameters":[{"name":"legacy","in":"query","required":false,"schema":{"type":"boolean","description":"Return the legacy short response format. Default is the unified validation report.","default":false,"title":"Legacy"},"description":"Return the legacy short response format. Default is the unified validation report."},{"name":"enrich","in":"query","required":false,"schema":{"type":"boolean","description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services.","default":true,"title":"Enrich"},"description":"Enable company identifier enrichment through the official French Sirene registry. When enabled, SIREN/SIRET values and company names/addresses found in the invoice may be checked against INSEE Sirene; recherche-entreprises.api.gouv.fr can be used as a public fallback. Set enrich=false when the request must not call those third-party public registry services."},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(en|fr)$"},{"type":"null"}],"description":"Response language (en or fr). Falls back to Accept-Language header if not specified.","title":"Lang"},"description":"Response language (en or fr). Falls back to Accept-Language header if not specified."},{"name":"validation_profile","in":"query","required":false,"schema":{"type":"string","pattern":"^(auto|facturx_en16931_base|facturx_extended|fr_ctc|extended_ctc_fr|chorus_b2g)$","description":"Validation target. Use facturx_en16931_base for EN16931-only. Use auto with jurisdiction=FR for the France 2026 target.","default":"auto","title":"Validation Profile"},"description":"Validation target. Use facturx_en16931_base for EN16931-only. Use auto with jurisdiction=FR for the France 2026 target."},{"name":"validation_target","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(en16931|france_2026)$"},{"type":"null"}],"description":"Explicit validation target selector. Use en16931 for Factur-X EN16931, or france_2026 for EN16931 plus available France 2026 / FNFE-MPE checks.","title":"Validation Target"},"description":"Explicit validation target selector. Use en16931 for Factur-X EN16931, or france_2026 for EN16931 plus available France 2026 / FNFE-MPE checks."},{"name":"jurisdiction","in":"query","required":false,"schema":{"type":"string","pattern":"^(UNKNOWN|FR|EU)$","description":"Caller-declared jurisdiction. auto + FR derives France CTC when the runtime is available.","default":"UNKNOWN","title":"Jurisdiction"},"description":"Caller-declared jurisdiction. auto + FR derives France CTC when the runtime is available."},{"name":"require_profile","in":"query","required":false,"schema":{"type":"boolean","description":"Kept for parity with /convert. Explicit validation_profile values already fail with 422 when unavailable.","default":false,"title":"Require Profile"},"description":"Kept for parity with /convert. Explicit validation_profile values already fail with 422 when unavailable."},{"name":"message_type","in":"query","required":false,"schema":{"type":"string","pattern":"^invoice$","description":"Message family to validate. /validate currently supports invoice CII.","default":"invoice","title":"Message Type"},"description":"Message family to validate. /validate currently supports invoice CII."},{"name":"en16931_next","in":"query","required":false,"schema":{"type":"boolean","description":"Attach en16931Next, the opt-in CEN EN16931 1.3.17 simulation. Default off. Does not change valid, errors, warnings, or validationReadiness.","default":false,"title":"En16931 Next"},"description":"Attach en16931Next, the opt-in CEN EN16931 1.3.17 simulation. Default off. Does not change valid, errors, warnings, or validationReadiness."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Idempotency key for replay-safe billing","title":"Idempotency-Key"},"description":"Idempotency key for replay-safe billing"},{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Public API key header, recommended for server integrations."},{"name":"Authorization","in":"header","required":false,"schema":{"type":"string"},"description":"API key bearer alias: Authorization: Bearer <api_key>. Prefer X-API-Key for new server integrations."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_validate_facturx_api_v1_validate_post"}}}},"responses":{"200":{"description":"Validation effectuée (succès ou échec)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnifiedValidationResponse"},{"$ref":"#/components/schemas/ValidationResponse"}],"title":"Response Validate Facturx Api V1 Validate Post"},"examples":{"valid":{"summary":"Facture valide - format unifié par défaut","value":{"valid":true,"validatedAt":"2026-04-28T10:00:00.000Z","filename":"invoice.xml","profile":"EN16931","durationMs":124,"summary":{"errorCount":0,"warningCount":0},"issues":[],"stages":{"pdfa":{"passed":true,"skipped":true,"skip_reason":"XML file - PDF/A validation not applicable","error_count":0,"warning_count":0,"info_count":0,"issues":[]},"facturx_pdf":{"passed":true,"skipped":true,"skip_reason":"XML file - PDF checks not applicable","error_count":0,"warning_count":0,"info_count":0,"issues":[]},"xsd":{"passed":true,"skipped":false,"error_count":0,"warning_count":0,"info_count":0,"issues":[]},"schematron":{"passed":true,"skipped":false,"error_count":0,"warning_count":0,"info_count":0,"issues":[]}},"errors":[],"warnings":[]}},"invalid_xsd":{"summary":"Erreur XSD - format unifié par défaut","value":{"valid":false,"validatedAt":"2026-04-28T10:00:00.000Z","filename":"invoice.xml","profile":"EN16931","durationMs":124,"summary":{"errorCount":1,"warningCount":0},"issues":[{"code":"XSD_VALIDATION_ERROR","severity":"error","stage":"xsd","message":"Missing required element: InvoiceNumber","line":42,"expected":"InvoiceNumber","location":"line 42","xpath":"/Invoice/ID"}],"stages":{"pdfa":{"passed":true,"skipped":true,"skip_reason":"XML file - PDF/A validation not applicable","error_count":0,"warning_count":0,"info_count":0,"issues":[]},"facturx_pdf":{"passed":true,"skipped":true,"skip_reason":"XML file - PDF checks not applicable","error_count":0,"warning_count":0,"info_count":0,"issues":[]},"xsd":{"passed":false,"skipped":false,"error_count":1,"warning_count":0,"info_count":0,"issues":[]},"schematron":{"passed":true,"skipped":false,"error_count":0,"warning_count":0,"info_count":0,"issues":[]}},"errors":[{"code":"XSD_VALIDATION_ERROR","severity":"error","stage":"xsd","message":"Missing required element: InvoiceNumber","line":42,"expected":"InvoiceNumber","location":"line 42","xpath":"/Invoice/ID"}],"warnings":[]}},"legacy":{"summary":"Format legacy avec ?legacy=true","value":{"valid":true,"errors":[],"warnings":[],"profile":"EN16931","message":"Validation completed"}}}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"Quota mensuel de factures traitées atteint (quota_exceeded)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"400":{"description":"Fichier vide ou invalide","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"413":{"description":"Fichier trop volumineux (file_too_large)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"415":{"description":"Type de fichier non supporté (unsupported_media_type)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"422":{"description":"Cible de validation explicite non exécutable (validation_profile_unavailable)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Rate limit dépassé (rate_limit_exceeded)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Validation engine indisponible (service_unavailable)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"Erreur serveur (stockage, traitement)","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}},"security":[{"PublicApiKeyHeader":[]},{"PublicApiKeyBearer":[]}]}},"/health":{"get":{"summary":"Health","description":"Health check endpoint with database ping + schema drift detection.\n\nSync handler so FastAPI runs the blocking D1 HTTP client in its\nthreadpool (``httpx.Client`` must not occupy the asyncio event loop —\nol_5224 / Astra finding). Database connectivity (``SELECT 1``) is\nprobed on every request. Schema canaries use a TTL cache with\nbounded stale-while-revalidate (ol_5783): after boot seeds the cache,\nprobes within ``SCHEMA_GUARD_HEALTH_MAX_STALE_SECONDS`` never wait on\nD1 for canary refresh; past max-stale the probe blocks synchronously\nso persistent ``check_error`` returns 503 again. Background\nsnapshot/serial refresh still rediscovers missing migrations without\nlengthening the TTL. Boot and ``validate_d1_schema`` still run\n:func:`verify_schema` uncached and fail closed.\n\nReturns:\n    - 200 ``{\"status\": \"ok\", \"db\": \"ok\", \"schema\": \"ok\"}`` when all\n      systems are operational.\n    - 503 ``{\"status\": \"degraded\", \"db\": \"error\"}`` when the DB is\n      unreachable.\n    - 503 ``{\"status\": \"degraded\", \"db\": \"ok\", \"schema\": \"drift\",\n      \"missing\": {<table>: [<col>...]}, \"missing_migrations\": [...]}``\n      when the connection works but D1 is missing canary columns or\n      required UNIQUE indexes from a migration the code depends on.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Health degraded because the database is unavailable or the schema drift guard failed.","headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}}}},"/healthz":{"get":{"summary":"Healthz","description":"Report process liveness without probing external dependencies.","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Healthz Healthz Get"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}}}},"/meta":{"get":{"tags":["meta"],"summary":"Public metadata (source of truth)","description":"Public, read-only metadata used as a single source of truth for versions, artefacts, limits, and plan quotas.","operationId":"get_meta_meta_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaResponse"}}},"headers":{"X-Request-ID":{"description":"Canonical UUID correlation identifier echoed from a valid request X-Request-ID header, or generated by the API when the caller omits or provides an invalid identifier.","schema":{"type":"string","format":"uuid"}}}}}}}},"components":{"schemas":{"ExtractResponse":{"properties":{"profile":{"type":"string","title":"Profile","description":"Detected Factur-X profile"},"xml":{"type":"string","title":"Xml","description":"Embedded Factur-X / CII / UBL XML, base64-encoded for safe JSON transport (decode with standard base64; not plaintext « XML brut »)."},"xmlSize":{"type":"integer","title":"Xmlsize","description":"Size of decoded XML in bytes"},"json":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Json","description":"Canonical invoice_data parsed from the embedded XML when parsing succeeds."},"jsonOmittedLines":{"anyOf":[{"$ref":"#/components/schemas/ExtractOmittedLines"},{"type":"null"}],"description":"Present when `json` leaves document lines out: the EXTENDED GROUP / INFORMATION lines, by BT-126 id. `json` alone is then not the whole document."},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"},"extractedAt":{"type":"string","title":"Extractedat"},"durationMs":{"type":"integer","title":"Durationms"},"validation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Validation"},"enrichment":{"anyOf":[{"$ref":"#/components/schemas/EnrichmentResult"},{"type":"null"}],"description":"Seller/buyer registry enrichment when Sirene enrichment ran for this call."},"processedInvoicesCharged":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Processedinvoicescharged","description":"Processed invoices charged for this extract call after settlement."},"remainingInvoices":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Remaininginvoices","description":"Remaining processed-invoice quota after this call, when known."},"quotaRefunded":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Quotarefunded","description":"Whether a previously reserved quota unit was refunded for this call."},"quotaSettlement":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Quotasettlement","description":"Machine-readable quota settlement receipt."}},"type":"object","required":["profile","xml","xmlSize","extractedAt","durationMs"],"title":"ExtractResponse","description":"Response from /extract endpoint.\n\nDefines the API response schema for extraction operations.\nUses aliases to provide camelCase keys in JSON responses.\n\nAttributes:\n    profile: Detected Factur-X profile name.\n    xml: Base64-encoded XML content (safe JSON transport; not plaintext XML).\n    xml_size: Size of XML in bytes.\n    json_data: Canonical invoice data parsed from the embedded XML.\n    filename: Original PDF filename (if available).\n    extracted_at: ISO timestamp of extraction.\n    duration_ms: Time taken for extraction in milliseconds.\n    validation: Optional validation result (if validate=True).\n    enrichment: Optional Sirene/company enrichment when enrich ran."},"UnifiedValidationResponse":{"properties":{"presentation_state":{"anyOf":[{"$ref":"#/components/schemas/PresentationState"},{"type":"null"}]},"decision_copy_key":{"anyOf":[{"type":"string","enum":["scan_presentation.can_generate_now","scan_presentation.unknown"]},{"type":"null"}],"title":"Decision Copy Key"},"primary_action":{"anyOf":[{"$ref":"#/components/schemas/PresentationAction"},{"type":"null"}]},"remaining_work":{"anyOf":[{"items":{"$ref":"#/components/schemas/PresentationWork"},"type":"array"},{"type":"null"}],"title":"Remaining Work"},"presentation_counts":{"anyOf":[{"$ref":"#/components/schemas/PresentationCounts"},{"type":"null"}]},"reportDecision":{"anyOf":[{"$ref":"#/components/schemas/ReportDecision"},{"type":"null"}]},"valid":{"type":"boolean","title":"Valid"},"nonEvaluation":{"anyOf":[{"$ref":"#/components/schemas/NonEvaluation"},{"type":"null"}],"description":"Present when valid is false because the requested target was not evaluated and the profile layer passed. Absent when a rule failed or the target was evaluated."},"validatedAt":{"type":"string","title":"Validatedat"},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"},"en16931Execution":{"anyOf":[{"$ref":"#/components/schemas/En16931ExecutionResponse"},{"type":"null"}],"description":"Optional canonical EN16931 execution evidence for the submitted source, independent of Proof Cards opt-in. A BASIC profile pass is not an EN16931 pass. executed=false or passed=null does not prove conformance; validationReadiness remains the scoped verdict. artifactVersion identifies the executed runtime pack. No raw SVRL is exposed. Absent when this execution evidence is not produced."},"en16931Next":{"anyOf":[{"$ref":"#/components/schemas/En16931NextUnavailable"},{"type":"object"},{"type":"null"}],"title":"En16931Next","description":"Opt-in simulation of CEN EN16931 1.3.17, in force on 2026-11-15. simulation is true. outcome is would_become_non_conforming, unchanged, or current_error_lifted. rules names the rule id and the engine message for a transition. coverageLimits lists measured delta rules this document did not fire. frenchPlatformsStillOn is 1.3.16. This block never changes valid, errors, warnings, or validationReadiness. Absent unless the caller passes en16931_next=true. When that caller asked and the simulation fails, the block is {status: unavailable, reason: simulation_failed | simulation_timeout | schematron_unavailable}. It is not omitted, and the failure is not a 5xx. A document refused for security (a DOCTYPE) is {status: not_evaluated, reason: input_refused}, never unavailable."},"durationMs":{"type":"integer","minimum":0.0,"title":"Durationms"},"summary":{"$ref":"#/components/schemas/ValidationSummaryResponse"},"issues":{"items":{"type":"object"},"type":"array","title":"Issues","description":"An item may carry ``correction``: the value to write for a failing rule, computed from the document and verified by a test that applies it and validates again — {kind: derived|input_required, bt, xpath, current, proposed, attributes?, requiresConfirmation?, dependsOn?, basis?, message}. ``requiresConfirmation`` means the value is a default to check (e.g. against the directory). For BT-34/BT-49, ``basis`` names its source: verified_routing / document_detected / suggested (the value ``convertPreparation`` serves for that field) or siren_default (the document's SIREN, only when the party has no SIRET). When a SIRET was read but yields no routing value, the correction is {kind: input_required, basis: siret_without_routing_value} with no ``proposed``."},"stages":{"additionalProperties":{"$ref":"#/components/schemas/ValidationStageResponse"},"type":"object","title":"Stages"},"errors":{"items":{"type":"object"},"type":"array","title":"Errors"},"warnings":{"items":{"type":"object"},"type":"array","title":"Warnings"},"remediationReport":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Remediationreport"},"enrichment":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Enrichment"},"validationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validationstatus","description":"Legacy coarse status for the submitted source validation. It is demoted to `error` when the requested target/profile was not evaluated (for example when validationReadiness.en16931 or validationReadiness.frCtc is not_evaluated/not_run) so clients do not present an unverified target as valid. Use validationReadiness and the lifecycle readiness fields for the executable verdict."},"validationScopeLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validationscopelabel"},"appliedValidationProfiles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Appliedvalidationprofiles"},"skippedValidationProfiles":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Skippedvalidationprofiles"},"unsupportedValidationProfiles":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Unsupportedvalidationprofiles"},"validationArtifacts":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Validationartifacts"},"messageType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Messagetype"},"legalDisclaimer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Legaldisclaimer"},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"Short scoped target contract. It preserves the requested/executed target and coarse status so clients do not infer scope from ``valid`` alone. Detailed executable truth lives in ``validationReadiness``."},"validationTarget":{"anyOf":[{"$ref":"#/components/schemas/ValidationTargetPolicyPayload"},{"type":"null"}]},"validationReadiness":{"anyOf":[{"$ref":"#/components/schemas/ValidationReadinessResponse"},{"type":"null"}],"description":"Five-layer Product Truth readiness (en16931, facturxProfile, frCtc, paAcceptance, packaging). The ``facturxProfile`` layer is the Factur-X runtime profile extension schematron — ``not_evaluated`` for EN16931-profile sources because the runtime only runs the CEN base schematron on that path. See ``docs/VALIDATION_TOPOLOGY.md`` §7."},"submittedSourceReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Submittedsourcereadiness","description":"Optional lifecycle readiness for the submitted source artifact only. For `/validate`, this describes the uploaded PDF/XML source when the runtime exposes that lifecycle layer; it is absent/null when the endpoint only returns the canonical validationReadiness block. Never use generated candidate or final generated validation evidence to mark the submitted source as ready."},"candidateValidationReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Candidatevalidationreadiness","description":"Optional lifecycle readiness for a generated candidate artifact. It is absent/null on a pure `/validate` request unless a surface has actually generated and validated a candidate. This field must not be folded into submittedSourceReadiness or into the legacy `valid` flag."},"finalGeneratedValidation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Finalgeneratedvalidation","description":"Optional lifecycle readiness for the final generated deliverable after actual generation/packaging. It is absent/null before final generation; clients must not infer final PDF/A-3 or France 2026 readiness from a source-only validation response."},"artifactLineage":{"allOf":[{"$ref":"#/components/schemas/CausalArtifactLineageResponse"}],"description":"Canonical runtime-produced source identity. Pure /validate has no candidate or generated output; lifecycle fields derive from this root."},"causalDecision":{"allOf":[{"$ref":"#/components/schemas/CausalDecisionContractResponse"}],"description":"API-owned decision and occurrence identities scoped to the submitted source artifact; no client-side severity/blocking recomputation."}},"type":"object","required":["valid","validatedAt","durationMs","summary","target","artifactLineage","causalDecision"],"title":"UnifiedValidationResponse","description":"Default /validate response format.\n\nThe legacy ValidationResponse shape is still available with ?legacy=true.","examples":[{"durationMs":124,"errors":[],"filename":"invoice.xml","issues":[],"profile":"EN16931","stages":{"facturx_pdf":{"error_count":0,"info_count":0,"issues":[],"passed":true,"skip_reason":"XML file - PDF checks not applicable","skipped":true,"warning_count":0},"pdfa":{"error_count":0,"info_count":0,"issues":[],"passed":true,"skip_reason":"XML file - PDF/A validation not applicable","skipped":true,"warning_count":0},"schematron":{"error_count":0,"info_count":0,"issues":[],"passed":true,"skipped":false,"warning_count":0},"xsd":{"error_count":0,"info_count":0,"issues":[],"passed":true,"skipped":false,"warning_count":0}},"summary":{"errorCount":0,"warningCount":0},"target":{"executed":"en16931","missing_inputs":[],"requested":"en16931","status":"verified","not_run_reason":null},"valid":true,"validatedAt":"2026-04-28T10:00:00.000Z","warnings":[]}]},"ValidationResponse":{"properties":{"valid":{"type":"boolean","title":"Valid","description":"True if the file is valid according to XSD and Schematron rules, False otherwise"},"nonEvaluation":{"anyOf":[{"$ref":"#/components/schemas/NonEvaluation"},{"type":"null"}],"description":"Present when valid is false because the requested target was not evaluated and the profile layer passed. Absent when a rule failed or the target was evaluated."},"errors":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Errors","description":"List of validation errors (XSD, Schematron, PDF processing)","examples":[[{"line":"42","message":"Missing required element: InvoiceNumber","type":"xsd_validation_error"}]]},"warnings":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Warnings","description":"List of validation warnings (non-blocking issues)","examples":[[{"message":"Recommended field missing","type":"schematron_report"}]]},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile","description":"Detected profile (MINIMUM, BASIC_WL, BASIC, EN16931, EN16931_UBL, XRECHNUNG_CIUS, EXTENDED, or UNKNOWN). EN16931_UBL is standalone UBL EN16931; XRECHNUNG_CIUS is XRechnung CIUS CII — neither is Factur-X.","examples":["EN16931","EN16931_UBL","XRECHNUNG_CIUS","BASIC","MINIMUM","EXTENDED"]},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Human-readable summary message","examples":["Validation completed","Validation failed","Validation incomplete"]},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"Short scoped target contract. Present so legacy clients can tell which target the ``valid`` flag applies to."}},"type":"object","required":["valid","target"],"title":"ValidationResponse","description":"Response from validation endpoint.\n\nContains the validation result with detailed errors and warnings.","examples":[{"errors":[],"message":"Validation completed","profile":"EN16931","target":{"executed":"en16931","missing_inputs":[],"requested":"en16931","status":"verified","not_run_reason":null},"valid":true,"warnings":[]},{"errors":[{"line":"5","message":"Element 'invoice': Missing child element(s). Expected is ( number ).","type":"xsd_validation_error"}],"message":"Validation failed","valid":false,"warnings":[]}]},"MetaResponse":{"properties":{"public_api_version":{"type":"string","title":"Public Api Version","description":"Public API version pinned by clients (semver). Mirrors versioning.public_api_version."},"product_truth_contract_version":{"type":"string","title":"Product Truth Contract Version","description":"Product Truth contract version (semver)."},"product_truth_contract_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Product Truth Contract Sha256","description":"SHA-256 checksum of the exact docs/PRODUCT_TRUTH_CONTRACT.md bytes shipped with this runtime. This is an integrity checksum for cross-repository comparison, not a signature or proof of authenticity."},"conversion_input_recipe_version":{"type":"string","title":"Conversion Input Recipe Version","description":"conversionInputRecipe schema version (semver)."},"versioning":{"$ref":"#/components/schemas/VersioningPolicyInfo"},"build":{"$ref":"#/components/schemas/BuildInfo"},"validation_engine":{"$ref":"#/components/schemas/ValidationEngineInfo"},"limits":{"$ref":"#/components/schemas/LimitsInfo"},"plans":{"anyOf":[{"items":{"$ref":"#/components/schemas/app__infrastructure__api__routes__meta__PlanInfo"},"type":"array"},{"type":"null"}],"title":"Plans"},"capabilities":{"$ref":"#/components/schemas/CapabilitiesInfo"},"links":{"$ref":"#/components/schemas/LinksInfo"}},"additionalProperties":true,"type":"object","required":["public_api_version","product_truth_contract_version","product_truth_contract_sha256","conversion_input_recipe_version","versioning","build","validation_engine","limits","capabilities","links"],"title":"MetaResponse"},"EnrichmentResult":{"properties":{"seller":{"anyOf":[{"$ref":"#/components/schemas/EnrichedEstablishment"},{"type":"null"}]},"buyer":{"anyOf":[{"$ref":"#/components/schemas/EnrichedEstablishment"},{"type":"null"}]},"semantic_checks":{"items":{"$ref":"#/components/schemas/SemanticCheck"},"type":"array","title":"Semantic Checks"},"source":{"type":"string","enum":["insee","data_gouv_fallback","cache","disabled"],"title":"Source"},"seller_lookup_status":{"type":"string","enum":["not_requested","success","not_found","invalid_format","unavailable","sources_conflict","last_confirmed_stale"],"title":"Seller Lookup Status","default":"not_requested"},"buyer_lookup_status":{"type":"string","enum":["not_requested","success","not_found","invalid_format","unavailable","sources_conflict","last_confirmed_stale"],"title":"Buyer Lookup Status","default":"not_requested"},"seller_identifier_candidate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Identifier Candidate"},"buyer_identifier_candidate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Identifier Candidate"},"seller_registry_owner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Registry Owner"},"seller_registry_cause":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Registry Cause"},"seller_registry_escape":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Registry Escape"},"buyer_registry_owner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Registry Owner"},"buyer_registry_cause":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Registry Cause"},"buyer_registry_escape":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Registry Escape"},"seller_registry_availability":{"anyOf":[{"type":"string","enum":["temporarily_unavailable"],"const":"temporarily_unavailable"},{"type":"null"}],"title":"Seller Registry Availability"},"buyer_registry_availability":{"anyOf":[{"type":"string","enum":["temporarily_unavailable"],"const":"temporarily_unavailable"},{"type":"null"}],"title":"Buyer Registry Availability"},"seller_last_confirmed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Last Confirmed At"},"buyer_last_confirmed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Last Confirmed At"},"seller_last_confirmed_age_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Seller Last Confirmed Age Seconds"},"buyer_last_confirmed_age_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Buyer Last Confirmed Age Seconds"},"seller_last_confirmed_stale":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Seller Last Confirmed Stale"},"buyer_last_confirmed_stale":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Buyer Last Confirmed Stale"}},"additionalProperties":false,"type":"object","required":["source"],"title":"EnrichmentResult","description":"Seller/buyer enrichment payload returned by the module."},"RepairResponse":{"properties":{"durationMs":{"type":"integer","title":"Durationms","description":"Time taken for repair in milliseconds"},"repaired_xml":{"type":"string","title":"Repaired Xml","description":"Base64-encoded repaired XML content"},"diff_summary":{"items":{"$ref":"#/components/schemas/DiffItemResponse"},"type":"array","title":"Diff Summary","description":"List of changes made during repair"},"changesCount":{"type":"integer","title":"Changescount","description":"Number of actual XML mutations applied during repair.","default":0},"wasModified":{"type":"boolean","title":"Wasmodified","description":"True when at least one actual XML mutation was applied.","default":false},"repairApplied":{"type":"boolean","title":"Repairapplied","description":"True when the endpoint applied at least one repair mutation.","default":false},"targetVerified":{"type":"boolean","title":"Targetverified","description":"True when the post-repair XML is verified for the requested target.","default":false},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"Canonical requested/executed target truth for the repaired XML. targetVerified=true is only valid when this target is verified."},"repairSuccessful":{"type":"boolean","title":"Repairsuccessful","description":"Whether a repair mutation was applied and the output XML was verified for the requested target. Must be false for verified no-op inputs and when target.status is not verified."},"validation_before":{"allOf":[{"$ref":"#/components/schemas/RepairValidationPayload"}],"description":"Validation result before repair"},"validation_after":{"allOf":[{"$ref":"#/components/schemas/RepairValidationPayload"}],"description":"Validation result after repair"},"processedInvoicesCharged":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Processedinvoicescharged","description":"Processed invoices charged for this repair call after settlement."},"remainingInvoices":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Remaininginvoices","description":"Remaining processed-invoice quota after this call, when known."},"quotaRefunded":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Quotarefunded","description":"Whether a previously reserved quota unit was refunded for this call."},"quotaSettlement":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Quotasettlement","description":"Machine-readable quota settlement receipt."}},"type":"object","required":["durationMs","repaired_xml","diff_summary","target","repairSuccessful","validation_before","validation_after"],"title":"RepairResponse","description":"Response from /repair endpoint.\n\nDefines the API response schema for repair operations.\nMatches the RepairResponse schema in OPENAPI.yaml.\n\nAttributes:\n    duration_ms: Time taken for repair in milliseconds.\n    repaired_xml: Base64-encoded repaired XML content.\n    diff_summary: List of changes made during repair.\n    target: Canonical requested/executed validation target truth.\n    validation_before: Validation result before repair.\n    validation_after: Validation result after repair."},"ExtractOmittedLines":{"properties":{"lineIds":{"items":{"type":"string"},"type":"array","title":"Lineids","description":"BT-126 ids of the GROUP / INFORMATION lines absent from `json.line_items`."},"reason":{"type":"string","enum":["extended_group_or_information_line"],"const":"extended_group_or_information_line","title":"Reason","description":"Why these lines are absent: EXTENDED BT-X-8 GROUP or INFORMATION lines carry no billable values."}},"type":"object","required":["lineIds","reason"],"title":"ExtractOmittedLines","description":"EXTENDED lines the canonical ``json`` leaves out (it models billable lines only)."},"ValidationReadinessResponse":{"properties":{"en16931":{"allOf":[{"$ref":"#/components/schemas/ValidationReadinessSectionResponse"}],"description":"Pure CEN EN16931 base schematron outcome. ``passed`` means the runtime CEN compiled XSLT found no error; it does NOT mean the Factur-X runtime profile extension layer was checked — see ``facturxProfile`` for that distinction."},"facturxProfile":{"allOf":[{"$ref":"#/components/schemas/ValidationReadinessSectionResponse"}],"description":"Factur-X runtime profile schematron outcome (the extension layer on top of CEN EN16931). The runtime only runs this layer for non-EN16931 source profiles (BASIC, BASIC_WL, EXTENDED, MINIMUM). For EN16931-profile sources the status is ``not_evaluated`` and ``evidence`` is ``factur_x_runtime_extensions_not_runtime_observed`` — see ``docs/VALIDATION_TOPOLOGY.md``."},"frCtc":{"allOf":[{"$ref":"#/components/schemas/ValidationReadinessSectionResponse"}],"description":"France CTC / FNFE-MPE outcome from the runtime pack actually executed. Only run for FR jurisdiction (auto-detected or explicit ``jurisdiction=FR``). Out-of-FR fixtures see ``status='not_evaluated'`` with ``evidence='out_of_france_ctc_scope'`` or similar."},"paAcceptance":{"allOf":[{"$ref":"#/components/schemas/ValidationReadinessSectionResponse"}],"description":"Plateforme Agréée acceptance lifecycle. Hard-locked to ``status='not_submitted'`` by the engine — PA acceptance is NEVER inferred from a green validation stack. The invariant validator (INV-025) refuses any drift."},"packaging":{"allOf":[{"$ref":"#/components/schemas/ValidationReadinessSectionResponse"}],"description":"PDF/A-3 packaging / Factur-X attachment registration outcome. ``passed`` when veraPDF + the Factur-X PDF checks service confirm the envelope; ``blocked`` when structural issues (XMP, /AF embedding) prevent a clean packaging; ``not_evaluated`` for xml_only dry-run mode."}},"additionalProperties":true,"type":"object","required":["en16931","facturxProfile","frCtc","paAcceptance","packaging"],"title":"ValidationReadinessResponse","description":"Five-layer Product Truth readiness contract.\n\nThe five layers are ALWAYS emitted (``facturxProfile`` was added in\n``task_9.md`` Phase 2 and is part of this contract). A caller can\nread each layer independently to tell exactly which schematron /\nvalidator ran. No higher-level field in the payload is allowed to\ncompress these five layers into a single positive answer — the\ninvariant validator in\n``app/domain/services/product_truth_invariants.py`` (INV-024 /\nINV-025 / INV-026) refuses to ship such a payload.","examples":[{"en16931":{"blockerCount":0,"blockers":[],"evidence":"en16931_base_passed","status":"passed"},"facturxProfile":{"blockerCount":0,"blockers":[],"evidence":"factur_x_runtime_extensions_not_runtime_observed","reason":"factur_x_runtime_profile_schematron_not_runtime_observable_for_en16931","status":"not_evaluated","target":"factur_x_runtime_extensions"},"frCtc":{"blockerCount":0,"blockers":[],"dependsOn":["target_profile_valid"],"evidence":"fr_ctc_passed","status":"passed","targetProfile":"en16931","targetProfileValid":true,"targetProfileValidEvaluated":true},"paAcceptance":{"blockerCount":0,"blockers":[],"evidence":"pa_lifecycle_not_part_of_validation_target","reason":"pa_lifecycle_not_part_of_validation_target","status":"not_submitted","target":"not_submitted"},"packaging":{"blockerCount":0,"blockers":[],"evidence":"packaging_passed","status":"passed"}},{"en16931":{"blockerCount":0,"blockers":[],"status":"passed"},"facturxProfile":{"blockerCount":0,"blockers":[],"evidence":"factur_x_runtime_extensions_not_runtime_observed","status":"not_evaluated"},"frCtc":{"blockerCount":1,"blockers":["BR-FR-12_BT-49"],"dependsOn":["target_profile_valid"],"evidence":"fr_ctc_failed_assert","status":"blocked","targetProfile":"en16931","targetProfileValid":true,"targetProfileValidEvaluated":true},"paAcceptance":{"blockerCount":0,"blockers":[],"status":"not_submitted"},"packaging":{"blockerCount":0,"blockers":[],"evidence":"packaging_skipped_xml_only","status":"not_evaluated"}}]},"PresentationWork":{"properties":{"requirement_id":{"type":"string","minLength":1,"title":"Requirement Id"},"category":{"type":"string","enum":["provide","confirm","correct_source","unknown"],"title":"Category"},"phase":{"type":"string","enum":["before_generation","before_transmission","unknown"],"title":"Phase"},"copy_key":{"type":"string","enum":["scan_presentation.work.provide","scan_presentation.work.confirm","scan_presentation.work.correct_source","scan_presentation.work.unknown"],"title":"Copy Key"},"field_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Field Path"},"target_scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Scope"},"rule_refs":{"items":{"type":"string"},"type":"array","title":"Rule Refs"},"member_refs":{"items":{"type":"string"},"type":"array","title":"Member Refs"}},"additionalProperties":false,"type":"object","required":["requirement_id","category","phase","copy_key","rule_refs","member_refs"],"title":"PresentationWork","description":"One producer-owned obligation; identities are carried, never synthesised."},"VersioningPolicyInfo":{"properties":{"public_api_version":{"type":"string","title":"Public Api Version","description":"Public API version pinned by clients (semver)."},"product_truth_contract_version":{"type":"string","title":"Product Truth Contract Version","description":"Version of the Product Truth contract (requirements, fieldProvenance, validationReadiness, conversionInputRecipe). Bumped on additive surface changes."},"conversion_input_recipe_version":{"type":"string","title":"Conversion Input Recipe Version","description":"Version of the conversionInputRecipe contract embedded in scan / convert dry-run responses."},"stability":{"type":"string","title":"Stability","description":"Stability tier (stable | preview | deprecated).","default":"stable"},"additive_only":{"type":"boolean","title":"Additive Only","description":"True when /api/v1 only ships additive (non-breaking) changes.","default":true},"breaking_changes_policy":{"type":"string","title":"Breaking Changes Policy","default":"Breaking changes require a new versioned prefix (/api/v2) with explicit migration notice — they are NEVER applied to /api/v1 in place."},"pa_acceptance_inferred":{"type":"boolean","title":"Pa Acceptance Inferred","description":"Plateforme Agréée acceptance is never inferred from API responses. PA lifecycle is always an external event.","default":false}},"additionalProperties":true,"type":"object","required":["public_api_version","product_truth_contract_version","conversion_input_recipe_version"],"title":"VersioningPolicyInfo","description":"Versioning policy that public clients pin against.\n\nThe public API at ``/api/v1`` is stable: only additive (non-breaking)\nchanges are made. Breaking changes ship a new prefix (``/api/v2``)\nwith explicit migration notice. Plateforme Agréée acceptance is\nNEVER inferred — it is always an external lifecycle event."},"ValidationTargetContractPayload":{"type":"object","title":"ValidationTargetContractPayload","description":"Legacy target contract retained for repair and compatibility surfaces."},"app__infrastructure__api__routes__meta__PlanInfo":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"monthly_quota":{"type":"integer","title":"Monthly Quota"},"price":{"anyOf":[{},{"type":"null"}],"title":"Price"}},"additionalProperties":true,"type":"object","required":["code","name","monthly_quota"],"title":"PlanInfo"},"PresentationAction":{"properties":{"action_id":{"type":"string","minLength":1,"title":"Action Id"},"copy_key":{"type":"string","enum":["scan_presentation.generate"],"const":"scan_presentation.generate","title":"Copy Key"},"kind":{"type":"string","enum":["generate"],"const":"generate","title":"Kind"},"operation_id":{"type":"string","minLength":1,"title":"Operation Id"},"artifact_id":{"type":"string","minLength":1,"title":"Artifact Id"},"target_scope":{"type":"string","enum":["en16931","france_2026"],"title":"Target Scope"},"requirement_ids":{"items":{"type":"string"},"type":"array","title":"Requirement Ids"},"decision_id":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Decision Id"}},"additionalProperties":false,"type":"object","required":["action_id","copy_key","kind","operation_id","artifact_id","target_scope","requirement_ids","decision_id"],"title":"PresentationAction","description":"A reference to an existing API-owned command, never a new permission."},"BuildInfo":{"properties":{"commit_sha":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commit Sha","description":"Git commit SHA for this build, if provided at build time"},"build_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Build Date","description":"Build date/time, if provided at build time"},"env":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Env","description":"Runtime environment identifier (development/production/test)"}},"additionalProperties":true,"type":"object","title":"BuildInfo"},"SemanticCheck":{"properties":{"rule_id":{"type":"string","title":"Rule Id"},"severity":{"type":"string","enum":["info","warning"],"title":"Severity"},"party":{"type":"string","enum":["seller","buyer"],"title":"Party"},"expected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected"},"declared":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Declared"},"message_human_readable":{"type":"string","title":"Message Human Readable"}},"additionalProperties":false,"type":"object","required":["rule_id","severity","party","message_human_readable"],"title":"SemanticCheck","description":"Semantic warning or informational notice derived from Sirene data."},"CausalDecisionContractResponse":{"properties":{"decisionId":{"type":"string","pattern":"^fxd_[A-Za-z0-9_-]{43}$","title":"Decisionid"},"artifactId":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$","title":"Artifactid"},"subjects":{"items":{"$ref":"#/components/schemas/CausalDecisionSubjectResponse"},"type":"array","title":"Subjects"},"actions":{"items":{"$ref":"#/components/schemas/CausalActionInstanceResponse"},"type":"array","title":"Actions"},"ownership":{"additionalProperties":{"type":"string","enum":["api"],"const":"api"},"type":"object","title":"Ownership"},"legacyProjection":{"type":"object","title":"Legacyprojection"}},"additionalProperties":false,"type":"object","required":["decisionId","artifactId","subjects","actions","ownership","legacyProjection"],"title":"CausalDecisionContractResponse"},"ValidationStageResponse":{"properties":{"passed":{"type":"boolean","title":"Passed"},"skipped":{"type":"boolean","title":"Skipped","default":false},"skip_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skip Reason"},"error_count":{"type":"integer","minimum":0.0,"title":"Error Count","default":0},"warning_count":{"type":"integer","minimum":0.0,"title":"Warning Count","default":0},"info_count":{"type":"integer","minimum":0.0,"title":"Info Count","default":0},"issues":{"items":{"type":"object"},"type":"array","title":"Issues"}},"type":"object","required":["passed"],"title":"ValidationStageResponse","description":"Result for one validation pipeline stage."},"ConvertAsyncAcceptedResponse":{"properties":{"request_id":{"type":"string","minLength":1,"title":"Request Id","description":"Non-empty correlation identifier for this accepted conversion. The same value is returned in the ``X-Request-Id`` header."},"success":{"type":"boolean","enum":[false],"const":false,"title":"Success","description":"Always false while the requested target has not completed."},"result":{"$ref":"#/components/schemas/ConvertAsyncProcessingResultResponse"},"target":{"$ref":"#/components/schemas/ValidationTargetContractPayload"}},"additionalProperties":false,"type":"object","required":["request_id","success","result","target"],"title":"ConvertAsyncAcceptedResponse","description":"Strict HTTP 202 envelope for an accepted async conversion."},"RepairValidationPayload":{"properties":{"valid":{"type":"boolean","title":"Valid","description":"Whether this validation pass is valid"},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"Target truth for this validation pass"},"summary":{"type":"object","title":"Summary","description":"Validation issue counters"}},"additionalProperties":true,"type":"object","required":["valid","target"],"title":"RepairValidationPayload","description":"Validation payload embedded in /repair before/after results."},"DiffItemResponse":{"properties":{"code":{"type":"string","title":"Code","description":"Type of repair action performed"},"path":{"type":"string","title":"Path","description":"XPath to the modified element"},"message":{"type":"string","title":"Message","description":"Description of the change made"},"beforeValue":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Beforevalue","description":"Original value before modification"},"afterValue":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aftervalue","description":"New value after modification"},"ruleReference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rulereference","description":"Validation rule that triggered this repair"},"changeCategory":{"allOf":[{"$ref":"#/components/schemas/RepairChangeCategory"}],"description":"Canonical classification: correction and normalization are XML mutations; warning requires manual review and is not a correction."}},"type":"object","required":["code","path","message","changeCategory"],"title":"DiffItemResponse","description":"A single change made during repair.\n\nRepresents one atomic modification applied during the repair process.\n\nAttributes:\n    code: Type of change (e.g., \"element_added\", \"value_changed\").\n    path: XPath to the modified element.\n    message: Localized description of the change.\n    before_value: Original value before change (if applicable).\n    after_value: New value after change (if applicable).\n    rule_reference: XSD/Schematron rule that triggered this repair.\n    change_category: Canonical Product Truth classification for the item."},"PresentationCounts":{"properties":{"unit":{"type":"string","enum":["obligation_rows"],"const":"obligation_rows","title":"Unit","default":"obligation_rows"},"coverage":{"type":"string","enum":["complete","partial","unknown"],"title":"Coverage"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"provide":{"type":"integer","minimum":0.0,"title":"Provide"},"confirm":{"type":"integer","minimum":0.0,"title":"Confirm"},"correct_source":{"type":"integer","minimum":0.0,"title":"Correct Source"},"unknown":{"type":"integer","minimum":0.0,"title":"Unknown"}},"additionalProperties":false,"type":"object","required":["coverage","total","provide","confirm","correct_source","unknown"],"title":"PresentationCounts","description":"Counts concern the projected obligation rows, not rules or actions."},"EnrichedEstablishment":{"properties":{"siren":{"type":"string","title":"Siren"},"denomination_officielle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Denomination Officielle"},"forme_juridique_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Forme Juridique Code"},"forme_juridique_libelle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Forme Juridique Libelle"},"date_creation":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Creation"},"tranche_effectifs_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tranche Effectifs Code"},"tranche_effectifs_libelle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tranche Effectifs Libelle"},"code_ape":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Ape"},"libelle_ape":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Libelle Ape"},"statut_diffusion":{"anyOf":[{"type":"string","enum":["O","P","N"]},{"type":"null"}],"title":"Statut Diffusion"},"is_active":{"type":"boolean","title":"Is Active"},"administrative_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Administrative Status"},"siret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Siret"},"denomination_usuelle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Denomination Usuelle"},"adresse_complete":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Adresse Complete"},"code_postal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Postal"},"commune":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commune"},"code_ape_etablissement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Ape Etablissement"},"is_siege":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Siege"},"enseigne_1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enseigne 1"}},"additionalProperties":false,"type":"object","required":["siren","is_active"],"title":"EnrichedEstablishment","description":"Establishment enrichment merged with company-level attributes."},"CausalArtifactLineageResponse":{"properties":{"submittedSource":{"$ref":"#/components/schemas/CausalArtifactResponse"},"dryRunCandidate":{"anyOf":[{"$ref":"#/components/schemas/CausalArtifactResponse"},{"type":"null"}]},"generatedOutput":{"anyOf":[{"$ref":"#/components/schemas/CausalArtifactResponse"},{"type":"null"}]}},"additionalProperties":false,"type":"object","required":["submittedSource"],"title":"CausalArtifactLineageResponse","description":"Canonical ``source → candidate → output`` response contract."},"ValidationTargetPolicyPayload":{"properties":{"en16931":{"$ref":"#/components/schemas/ValidationTargetEn16931Response"},"frCtc":{"$ref":"#/components/schemas/ValidationTargetFrCtcResponse"},"jurisdiction":{"$ref":"#/components/schemas/ValidationTargetJurisdictionResponse"},"requestedProfile":{"type":"string","enum":["auto","facturx_en16931_base","facturx_extended","fr_ctc","chorus_b2g"],"title":"Requestedprofile"},"paLifecycle":{"$ref":"#/components/schemas/ValidationTargetPaLifecycleResponse"}},"additionalProperties":false,"type":"object","required":["en16931","frCtc","jurisdiction","requestedProfile","paLifecycle"],"title":"ValidationTargetPolicyPayload","description":"Public validation target policy shared by /convert, /scan, and /validate."},"ValidationTargetJurisdictionResponse":{"properties":{"requested":{"type":"string","enum":["UNKNOWN","FR","EU"],"title":"Requested"},"effectiveForResolver":{"type":"string","enum":["UNKNOWN","FR","EU"],"title":"Effectiveforresolver","description":"Jurisdiction passed to the executable profile resolver after policy conflicts are exposed."}},"additionalProperties":false,"type":"object","required":["requested","effectiveForResolver"],"title":"ValidationTargetJurisdictionResponse","description":"Requested jurisdiction and effective resolver jurisdiction."},"LimitsInfo":{"properties":{"max_upload_size_bytes":{"type":"integer","title":"Max Upload Size Bytes"},"accepted_formats":{"items":{"type":"string"},"type":"array","title":"Accepted Formats"},"rate_limit_enabled":{"type":"boolean","title":"Rate Limit Enabled"},"rate_limit_requests_per_minute":{"type":"integer","title":"Rate Limit Requests Per Minute"},"rate_limit_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rate Limit Mode"}},"additionalProperties":true,"type":"object","required":["max_upload_size_bytes","accepted_formats","rate_limit_enabled","rate_limit_requests_per_minute"],"title":"LimitsInfo"},"Body_validate_facturx_api_v1_validate_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"Fichier XML ou PDF Factur-X à valider (limite configurable via MAX_UPLOAD_SIZE_BYTES)","examples":["facture.xml","invoice.pdf"]}},"type":"object","required":["file"],"title":"Body_validate_facturx_api_v1_validate_post"},"Body_repair_facturx_xml_api_v1_repair_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"XML file to repair (Factur-X/EN16931 format)"},"constraints":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Constraints","description":"JSON object with repair constraints (optional)"}},"type":"object","required":["file"],"title":"Body_repair_facturx_xml_api_v1_repair_post"},"ValidationTargetFrCtcResponse":{"properties":{"target":{"type":"string","enum":["requested","applicable_by_default","not_applicable","unresolved","conflict","unavailable","runtime_error"],"title":"Target","description":"France CTC target status: requested, derived by default, not applicable, conflicted, unavailable, or runtime_error."},"reason":{"type":"string","enum":["explicit_validation_profile_fr_ctc","explicit_validation_profile_en16931_only","request_jurisdiction_fr","document_country_fr","request_jurisdiction_non_fr","request_document_jurisdiction_conflict","request_jurisdiction_fr_document_country_non_fr_conflict","document_country_non_fr","jurisdiction_unknown_no_document_country","document_seller_scope_unresolved","feature_flag_disabled","artifact_unavailable","runtime_not_implemented","artifact_runtime_error"],"title":"Reason","description":"Stable reason code explaining why this France CTC target status was chosen."},"source":{"type":"string","enum":["request","document","request_document","none"],"title":"Source","description":"Whether the decision came from the request, document evidence, both, or neither."},"conflict":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Conflict","description":"Stable conflict code when request jurisdiction and document evidence disagree."},"documentEvidence":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetDocumentEvidenceResponse"}],"description":"Country evidence considered by the target resolver."},"execution":{"anyOf":[{"$ref":"#/components/schemas/ValidationTargetExecutionResponse"},{"type":"null"}],"description":"Non-execution details when France CTC was targeted but skipped by runtime gates."}},"additionalProperties":false,"type":"object","required":["target","reason","source","documentEvidence"],"title":"ValidationTargetFrCtcResponse","description":"France CTC target decision and evidence."},"Body_extract_facturx_api_v1_extract_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"PDF file to extract XML from (Factur-X format)"}},"type":"object","required":["file"],"title":"Body_extract_facturx_api_v1_extract_post"},"ConvertResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the requested validation_target was verified. Processing or target-not-verified responses must use success=false.","default":true},"request_id":{"type":"string","minLength":1,"title":"Request Id","description":"Non-empty correlation identifier for this conversion response. The same value is also returned in the ``X-Request-Id`` header."},"artifactLineage":{"allOf":[{"$ref":"#/components/schemas/CausalArtifactLineageResponse"}],"description":"Canonical runtime-produced causal identity chain. Legacy lifecycle identity fields are projections of this object, never its authority."},"causalDecision":{"allOf":[{"$ref":"#/components/schemas/CausalDecisionContractResponse"}],"description":"API-owned stable decision, occurrence-subject and action-instance identities. Legacy requirement/action identifiers are projections."},"executionReceipt":{"anyOf":[{"$ref":"#/components/schemas/ExecutionReceiptResponse"},{"type":"null"}],"description":"Post-generation receipt. status=proven requires XSD and Schematron on the XML re-read from the final PDF and PDF/A on that PDF, each bound to that artifact's digest and executed with result passed. status=not_proven is only a control that was not executed, or a verifier that returned no result; that receipt still carries the lineage. An executed control with result failed is known invalidity: the conversion is refused and this field is absent from any success body. A PDF that cannot be re-read is not_proven with reason, owner and escape and no lineage. Never a control copied from the candidate."},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"Short scoped target contract for compatibility and async intent. It preserves requested/executed/status so clients do not infer scope from ``success`` alone; detailed executable truth lives in ``validationReadiness``."},"result":{"$ref":"#/components/schemas/ConvertResultResponse"},"targetPreflight":{"anyOf":[{"$ref":"#/components/schemas/TargetPreflightContractResponse"},{"type":"null"}],"description":"France 2026-only dry-run preflight contract, omitted for ``validation_target=en16931``. For ``validation_target=france_2026``, clients must use this object to decide whether the France 2026 checklist is complete, incomplete, unsupported, or failed; ``exhaustive=true`` is emitted only after candidate validation or an equivalent deterministic proof."},"draftCandidate":{"anyOf":[{"$ref":"#/components/schemas/DraftCandidatePreviewResponse"},{"type":"null"}],"description":"Optional non-exchangeable target-preflight preview. It is produced from synthetic dry-run probe values only; exchangeable=false and valid=false are load-bearing and clients must replay confirmed inputs in final /convert before treating an artifact as valid."},"dry_run":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Dry Run","description":"``true`` on dry-run responses (no quota consumed, no PDF produced). Absent on real convert responses."},"verdict":{"anyOf":[{"type":"string","enum":["ready","auto_repairable","needs_confirmation","convert_with_inputs","profile_upgrade_required","convert_incomplete","source_correction_required","erp_complete","target_not_evaluated","unsupported"]},{"type":"null"}],"title":"Verdict","description":"Dry-run verdict bucket. Closed domain (any other value is a contract violation): ``ready`` (validation passed), ``auto_repairable`` (engine fixes every remaining issue automatically — structural fixes or field-level repair from extraction evidence), ``needs_confirmation`` (every remaining issue is a candidate the user must confirm before ``/convert`` — typically a SIRET/SIREN found in an untrusted zone of the PDF), ``convert_with_inputs`` (the document can go through ``/convert`` after the supported business inputs listed in ``conversionInputRecipe.requiredInputs`` are provided; ``beforeTransmissionInputs`` remain non-blocking for local generation), ``profile_upgrade_required`` (the submitted lower Factur-X profile is readable but needs supported invoice_data to generate an EN16931 candidate), ``convert_incomplete`` (conversion can run now with zero generation-blocking inputs, but the requested target still needs a generated candidate (for example, a source PDF with no embedded EN16931 source and zero measured automatic fixes), or carries unresolved advisories, optional enrichments, or before-transmission obligations before it can be treated as fully ready), ``source_correction_required`` (deterministically invalid source values must be corrected before any generation attempt), ``erp_complete`` (legacy alias for older clients; new responses should use ``convert_with_inputs``), ``target_not_evaluated`` (the requested target was not run by the current runtime; no ready/conformant target claim is made), ``unsupported`` (genuine blocker / exception case)."},"apiCapability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Apicapability","description":"Legacy capability projection emitted on dry-run responses. Clients should prefer productTruthModel.generationCapability."},"issues":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Issues","description":"Dry-run issue list (each item carries the same fields as ``result.validation.issues``). An item may carry ``correction``: the value to write for a failing rule, computed from the document and verified by a test that applies it and validates again — {kind: derived|input_required, bt, xpath, current, proposed, attributes?, requiresConfirmation?, dependsOn?, basis?, message}. ``requiresConfirmation`` means the value is a default to check (e.g. against the directory). For BT-34/BT-49, ``basis`` names its source: verified_routing / document_detected / suggested (the value ``convertPreparation`` serves for that field) or siren_default (the document's SIREN, only when the party has no SIRET). When a SIRET was read but yields no routing value, the correction is {kind: input_required, basis: siret_without_routing_value} with no ``proposed``."},"extracted_data":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Extracted Data","description":"Sanitised view of the data the engine would feed into ``/convert`` (no PDF/XML content)."},"missing_fields":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Missing Fields","description":"Business fields the engine could not extract; the caller must provide them via ``invoice_data`` JSON to reach a conformant XML."},"recoverable_with_invoice_data":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Recoverable With Invoice Data","description":"``true`` when at least one ``erp_must_complete`` issue is present, signalling the caller can repair via ``invoice_data``."},"requirements":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Requirements","description":"Typed Product Truth requirements. This replaces any generic 'ERP required' interpretation with explicit requirement types such as seller_profile_required, fr_ctc_blocker, or pa_status_pending."},"fieldProvenance":{"anyOf":[{"additionalProperties":{"type":"object"},"type":"object"},{"type":"null"}],"title":"Fieldprovenance","description":"Per-critical-field provenance. Separates document/XML evidence, deterministic normalization, profile input, and missing values."},"conflicts":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Conflicts","description":"Typed conflicts between document evidence and profile or invoice override input. Conflicts are surfaced instead of silently overwriting visible document data."},"validationReadiness":{"anyOf":[{"$ref":"#/components/schemas/ValidationReadinessResponse"},{"type":"null"}],"description":"Five-layer Product Truth readiness contract (en16931, facturxProfile, frCtc, paAcceptance, packaging). The ``facturxProfile`` layer is the Factur-X runtime profile extension schematron — ``not_evaluated`` for EN16931-profile sources because the runtime only runs the CEN base schematron on that path. PA acceptance is hard-locked to ``not_submitted`` — never inferred from a green scan. See ``docs/VALIDATION_TOPOLOGY.md`` §7 for the full France-first claim policy."},"france2026Projection":{"anyOf":[{"$ref":"#/components/schemas/France2026ProjectionResponse"},{"type":"null"}],"description":"Double-regime France 2026 projection shared by API and product surfaces. A not_evaluated future regime carries null counts, never an inferred zero."},"generationReadiness":{"anyOf":[{"$ref":"#/components/schemas/GenerationReadinessResponse"},{"type":"null"}],"description":"Inputs that block local Factur-X generation only."},"transmissionReadiness":{"anyOf":[{"$ref":"#/components/schemas/TransmissionReadinessResponse"},{"type":"null"}],"description":"Inputs required before France 2026 routing/transmission."},"submittedSourceReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Submittedsourcereadiness","description":"Lifecycle readiness for the submitted source artifact only. It separates uploaded PDF/XML source truth from generated-candidate truth: for example, a source PDF without embedded Factur-X XML can have a generated candidate that validates while the submitted source remains not_evaluated for that target. Clients must not treat candidate readiness as source-document readiness."},"candidateValidationReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Candidatevalidationreadiness","description":"Lifecycle readiness for a generated candidate artifact, when a dry-run or scan/convert surface actually generated and validated one. This field is separate from submittedSourceReadiness and from finalGeneratedValidation; it is discovery/repair evidence. Clients must not use it as proof that the submitted source or final deliverable is ready."},"finalGeneratedValidation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Finalgeneratedvalidation","description":"Lifecycle readiness for the final generated deliverable after actual generation and packaging. It is absent/null before final generation and must not be inferred from source validation or candidate validation alone."},"productTruthModel":{"anyOf":[{"$ref":"#/components/schemas/ProductTruthModelResponse"},{"type":"null"}],"description":"Single causal Product Truth model emitted by the API for rendering scan, report, email and conversion surfaces without client-side target heuristics. It separates submitted file/XML truth, generation capability, generated candidate validation, France 2026 applicability/actions, identity verification and PA lifecycle. Clients should render status, counters and CTA capability from this object instead of re-counting issues or inferring state from the requested target name."},"conversionInputRecipe":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Conversioninputrecipe","description":"Product Truth conversion recipe explaining which missing or detected inputs are required before generation, required before transmission, or optional; which values can be supplied through the current /convert contract; which inputs are API gaps; and which nonRunnableDecisions fail closed as explicit product decisions rather than available public actions."},"convertPreparation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Convertpreparation","description":"Scanner-facing `/convert` handoff grouped into extracted fields, suggested values, confirmations, user-provided values, fields required before transmission, genuinely optional improvements, unsupported API gaps, and non-runnable product decisions. Clients should prefer this view for UI counts instead of reclassifying any conversionInputRecipe bucket."},"nextAction":{"anyOf":[{"$ref":"#/components/schemas/ConvertNextActionResponse"},{"type":"null"}],"description":"Canonical dry-run next action. Present on dry-run responses so clients do not infer convertability from legacy verdict or summary counters. Absent on real conversion responses."},"diagnostics":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Diagnostics","description":"Free-form diagnostic entries surfaced on the dry-run error branch (``_format_convert_dry_run_error_response``). Each entry is a schema-less dict so the engine can carry arbitrary remediation hints; clients should treat unknown keys as forward-compatible."},"error":{"anyOf":[{"type":"string","enum":["target_validation_failed"],"const":"target_validation_failed"},{"type":"null"}],"title":"Error","description":"Stable top-level machine error for final conversion responses where the requested target executed and failed validation. Absent on success, dry-run business responses, and target non-execution paths."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Localized human-readable explanation paired with ``error``."},"detail":{"anyOf":[{"$ref":"#/components/schemas/FinalConvertTargetValidationFailureDetailResponse"},{"type":"null"}],"description":"Typed detail for ``target_validation_failed``. Carries the failed target contract and the blocking validation rules so clients do not infer from ``success=false`` or ``target.status`` alone."}},"type":"object","required":["request_id","artifactLineage","causalDecision","target","result"],"title":"ConvertResponse","description":"Full response from /convert endpoint — success / dry-run\nbusiness path only.\n\nWraps the conversion result with top-level metadata. Covers:\n\n* **normal convert** — ``success`` + ``result``;\n* **dry-run business success / business error** (XML-upload path\n  and ``dry_run=true`` PDF where extraction succeeded) — adds\n  ``dry_run``, ``verdict``, ``issues``, ``extracted_data``,\n  ``missing_fields``, ``recoverable_with_invoice_data``.\n\nThe dry-run **extraction-failure** branch (where extraction\nfailed before validation could run) lives on a dedicated sibling\nenvelope :class:`ConvertDryRunErrorEnvelopeResponse` — published\nas a separate ``oneOf`` arm on the operation 200 schema. Its\n``result`` is a strict :class:`ConvertResultDryRunErrorResponse`\n(extraction null, locked-empty applied / artifacts, scope label\n``\"(no profile applied)\"``). That envelope cannot be expressed via this class —\n``result`` here is the success-mode shape only, with a mandatory\nextraction report.\n\nA ``model_validator`` rejects bodies that wear dry-run error\nmarkers (``success=False``, ``dry_run=True``, ``diagnostics``\nset) because those markers belong on the strict envelope: any\nsuch body must use ``ConvertDryRunErrorEnvelopeResponse`` and\ncarry the strict :class:`ConvertResultDryRunErrorResponse`\nresult. This closes the bypass Codex flagged on review 10 (a\nmutated body with success-shape ``result`` plus dry-run error\nmarkers would otherwise validate against this envelope).","examples":[{"request_id":"req_01JEXAMPLE","result":{"appliedValidationProfiles":["facturx_en16931_base"],"conversionSuccessful":true,"convertedAt":"2026-01-04T12:00:00+00:00","durationMs":2500,"extraction":{"pageCount":1,"sourceType":"native_text"},"legalDisclaimer":"Validation technique documentaire. Ne vaut pas acceptation par une Plateforme Agréée ni conformité fiscale finale.","messageType":"invoice","packagingPerformed":true,"pdf":"JVBERi0xLjQK...","pdfSize":102400,"processedInvoicesCharged":1,"remainingInvoices":99,"skippedValidationProfiles":[{"profile":"fr_ctc","reason":"feature_flag_disabled"}],"targetProfile":"EN16931","unsupportedValidationProfiles":[],"validation":{"profile":"EN16931","valid":true},"validationArtifacts":[{"id":"facturx-1.09.2-en16931-cii","family":"facturx","profile":"facturx_en16931_base","syntax":"cii","version":"1.09.2","sourceAuthority":"FNFE-MPE","sha256":"67f03050e3add4c83dc93de36e4501f6a11aae1ac790b3f9558feb0581019bcb","status":"available","executed":true}],"validationScopeLabel":"Factur-X EN16931 base","validationStatus":"valid","xml":"PD94bWwgdmVyc2lvbj0...","xmlSize":4096},"success":true,"target":{"executed":"en16931","missing_inputs":[],"requested":"en16931","status":"verified","not_run_reason":null}}]},"TransmissionReadinessResponse":{"properties":{"status":{"type":"string","enum":["ready","needs_input","blocked","not_evaluated"],"title":"Status"},"requiredBeforeTransmissionCount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Requiredbeforetransmissioncount"},"blocksTransmission":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Blockstransmission"},"reason":{"type":"string","title":"Reason"}},"additionalProperties":false,"type":"object","required":["status","requiredBeforeTransmissionCount","blocksTransmission","reason"],"title":"TransmissionReadinessResponse"},"En16931NextUnavailable":{"properties":{"status":{"type":"string","enum":["unavailable"],"const":"unavailable","title":"Status"},"reason":{"type":"string","enum":["simulation_failed","simulation_timeout","schematron_unavailable"],"title":"Reason"}},"type":"object","required":["status","reason"],"title":"En16931NextUnavailable","description":"Opt-in 1.3.17 simulation the caller asked for and that did not finish.\n\nThe served 1.3.16 verdict is unchanged. This block is not a 5xx."},"Body_convert_invoice_api_v1_convert_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File","description":"PDF invoice to convert. For output=facturx_pdfa3, upload this PDF as the visual carrier or provide a full invoice_data payload so the API can render the carrier from structured invoice data. A valid Factur-X CII XML (BASIC or EN16931) is also accepted as the sole source; its carrier is rendered from the XML data. A validated UBL Invoice/CreditNote is also accepted when every source field is supported by the strict UBL-to-CII mapper; otherwise the API returns ubl_source_mapping_unsupported. For output=xml_cii with full invoice_data, the upload is optional and no PDF/A-3 carrier is produced."},"options":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Options","description":"JSON object with conversion options (optional). Prefer validation_target (en16931 or france_2026). Legacy target controls remain supported: validation_profile values auto, facturx_en16931_base, facturx_extended, fr_ctc, extended_ctc_fr, chorus_b2g; jurisdiction values UNKNOWN, FR, EU; require_profile; message_type=invoice. output_profile is the requested profile; when invoice_data.payer is present the effective profile is promoted to EXTENDED, and result.targetProfile is authoritative."},"validation_target":{"anyOf":[{"type":"string","pattern":"^(en16931|france_2026)$"},{"type":"null"}],"title":"Validation Target","description":"Explicit verification target. Use en16931 for Factur-X EN16931, or france_2026 for EN16931 plus available France 2026 / FNFE-MPE checks."},"output":{"anyOf":[{"type":"string","pattern":"^(facturx_pdfa3|xml_cii)$"},{"type":"null"}],"title":"Output","description":"Deliverable selector. facturx_pdfa3 (default) returns the generated Factur-X PDF/A-3 using the uploaded PDF as carrier, or a carrier rendered from full invoice_data when no file is provided. xml_cii returns only the generated CII XML, normally in the requested options.output_profile, in result.xml; no PDF/A-3 packaging is performed and the deliverable is a CII XML file, not a Factur-X document. When invoice_data.payer is present, the effective profile is promoted to EXTENDED; result.targetProfile is authoritative for the profile actually emitted."},"invoice_data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Data","description":"JSON structured invoice data from ERP (optional). When provided, PDF text parsing is skipped. Validated against ErpInvoiceData (extra=forbid).\n\nEXT-FR-FE-BG-02 third-party payer (optional object `payer`, 0..1): the party that pays when it differs from the buyer. Distinct from `payee` (BG-10) and from `payment.debtor_account_iban` (BT-91). Presence of payer never invents BT-113 prepaid amounts. Because PayerTradeParty is outside lower Factur-X profiles, `payer` forces the effective output profile to `EXTENDED`, even when a lower `options.output_profile` was requested; `result.targetProfile` is authoritative for the profile actually emitted.\n\npayer shape:\n- name (required string): payer display name\n- global_id (optional): {value, scheme_id} both required when present\n- legal_registration (optional): {value, scheme_id} both required when present\n- postal_address (optional): {street, city, postal_code, country}; country is required when the object is present\n- email (optional): payer contact email under DefinedTradeContact; it is not the routing electronic_address\n- electronic_address (optional): {value, scheme_id} both required when present; value is EXT-FR-FE-52 (PayerTradeParty URIID, max 125 chars), scheme_id is EXT-FR-FE-53 (not seller BT-34 / buyer BT-49); France CTC electronic address uses scheme_id=0225\n- identifier is NOT accepted (extra=forbid → HTTP 422)\n\nMinimal payer example embedded in invoice_data JSON:\n{\"payer\":{\"name\":\"OPCO Formation SA\",\"global_id\":{\"value\":\"99999300900029\",\"scheme_id\":\"0009\"},\"legal_registration\":{\"value\":\"999993009\",\"scheme_id\":\"0002\"},\"postal_address\":{\"street\":\"12 rue de la Formation\",\"city\":\"Paris\",\"postal_code\":\"75008\",\"country\":\"FR\"},\"email\":\"facturation@opco.example\",\"electronic_address\":{\"value\":\"999993009\",\"scheme_id\":\"0225\"}}}","examples":["{\"invoice_number\":\"FX-PAYER-001\",\"issue_date\":\"2026-01-15\",\"invoice_type\":\"380\",\"currency\":\"EUR\",\"seller\":{\"name\":\"Vendeur Demo SAS\",\"address\":{\"country\":\"FR\",\"street\":\"1 rue du Test\",\"city\":\"Paris\",\"postal_code\":\"75002\"},\"vat_id\":\"FR09999991235\",\"siret\":\"99999123500014\"},\"buyer\":{\"name\":\"Acheteur Demo SARL\",\"address\":{\"country\":\"FR\",\"street\":\"2 avenue Client\",\"city\":\"Lyon\",\"postal_code\":\"69001\"},\"vat_id\":\"FR83999992456\",\"siret\":\"99999245600015\"},\"totals\":{\"net\":\"1000.00\",\"tax\":\"200.00\",\"gross\":\"1200.00\"},\"tax_breakdown\":[{\"rate\":\"20\",\"category\":\"S\",\"base\":\"1000.00\",\"amount\":\"200.00\"}],\"line_items\":[{\"number\":\"1\",\"description\":\"Prestation\",\"quantity\":\"1\",\"unit\":\"C62\",\"unit_price\":\"1000.00\",\"net_amount\":\"1000.00\",\"vat_rate\":\"20\",\"vat_category\":\"S\"}],\"payment\":{\"due_date\":\"2026-02-15\",\"iban\":\"FR7630006000011234567890189\"},\"delivery\":{\"date\":\"2026-01-15\"},\"payer\":{\"name\":\"OPCO Formation SA\",\"global_id\":{\"value\":\"99999300900029\",\"scheme_id\":\"0009\"},\"legal_registration\":{\"value\":\"999993009\",\"scheme_id\":\"0002\"},\"postal_address\":{\"street\":\"12 rue de la Formation\",\"city\":\"Paris\",\"postal_code\":\"75008\",\"country\":\"FR\"},\"email\":\"facturation@opco.example\",\"electronic_address\":{\"value\":\"999993009\",\"scheme_id\":\"0225\"}}}"]},"invoice_patch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Patch","description":"JSON invoice-specific patch applied after PDF extraction. Supports preceding_invoice.issue_date (BT-26), optional matching preceding_invoice.reference, payment.iban (BT-84), and invoicing_period.start_date/end_date (BG-14). Cannot be combined with full invoice_data."},"seller_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Context","description":"Optional JSON request object for BT-34/BT-22 complements. Under the current France CTC pack, BT-34 and PMT/PMD/AAB are all pinned fatal and required before France 2026 transmission; none of them automatically blocks local generation. Under an explicit 1.3.1 rollback they carry the rollback pack's own real (advisory) severity instead. electronic_address.value is max 125 chars; scheme_id is alphanumeric 2-20 chars. document_notes[] requires a UNCL4451 subject_code (BT-21; PMT/PMD/AAB are the France 2026 legal mentions) and content max 500 chars; untyped notes are rejected."},"seller_profile_inline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Profile Inline","description":"Alias for seller_context; no persistent profile is created or updated."},"buyer_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Context","description":"Optional JSON request object for BT-49 and alternate BT-22 document_notes. Under the current France CTC pack, BT-49 and PMT/PMD/AAB are all pinned fatal and required before France 2026 transmission; none of them automatically blocks local generation. Under an explicit 1.3.1 rollback they carry the rollback pack's own real (advisory) severity instead. electronic_address.value is max 125 chars; scheme_id is alphanumeric 2-20 chars. document_notes[] requires a UNCL4451 subject_code (BT-21; PMT/PMD/AAB are the France 2026 legal mentions) and content max 500 chars; untyped notes are rejected."},"buyer_profile_inline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Profile Inline","description":"Alias for buyer_context; no persistent profile is created or updated."},"issuer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuer Id","description":"Tenant-scoped saved issuer selector for explicit profile reuse; requires profile_reuse=explicit."},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id","description":"Tenant-scoped saved client selector for explicit profile reuse; requires profile_reuse=explicit."},"issuer_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Issuer Profile Id","description":"Alias for issuer_id; tenant-scoped and requires profile_reuse=explicit."},"client_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Profile Id","description":"Alias for client_id; tenant-scoped and requires profile_reuse=explicit."},"seller_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seller Profile Id","description":"Tenant-scoped saved seller profile selector; requires profile_reuse=explicit."},"buyer_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyer Profile Id","description":"Tenant-scoped saved buyer profile selector; requires profile_reuse=explicit."},"profile_reuse":{"anyOf":[{"type":"string","enum":["explicit"],"const":"explicit"},{"type":"null"}],"title":"Profile Reuse","description":"Saved-profile reuse policy. Use profile_reuse=explicit to allow tenant-scoped saved issuer/client fields to complete supported France 2026 / FNFE-MPE gaps."},"dry_run":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Dry Run","description":"Legacy multipart alias for the dry_run query parameter. Dry-run executes without monthly quota consumption and produces no final deliverable. Every explicit dry-run control must match."},"preview":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Preview","description":"Legacy multipart preview alias for dry_run, intended for workshop clients that should not expose internal diagnostic naming. Every explicit dry-run control must match."}},"type":"object","title":"Body_convert_invoice_api_v1_convert_post"},"CapabilitiesInfo":{"properties":{"supports_facturx_runtime_xsd":{"type":"boolean","title":"Supports Facturx Runtime Xsd"},"supports_en16931_compiled_xslt":{"type":"boolean","title":"Supports En16931 Compiled Xslt"},"supports_pdfa_via_verapdf":{"type":"boolean","title":"Supports Pdfa Via Verapdf"},"facturx_runtime_schematron_guaranteed":{"type":"boolean","title":"Facturx Runtime Schematron Guaranteed","description":"True when Factur-X runtime Schematron validation for all profiles is guaranteed (Saxon available and compiled artefacts bundled)."},"supports_extract":{"type":"boolean","title":"Supports Extract","description":"True when POST /api/v1/extract endpoint is available. Always true as extraction has no external dependencies.","default":true},"supports_repair":{"type":"boolean","title":"Supports Repair","description":"True when POST /api/v1/repair endpoint is available. Requires Saxon processor for Schematron validation.","default":false},"convert_endpoint_available":{"type":"boolean","title":"Convert Endpoint Available","description":"True when POST /api/v1/convert is mounted and callable. This does not imply every output mode is available."},"convert_xml_cii_available":{"type":"boolean","title":"Convert Xml Cii Available","description":"True when /convert can generate and validate final XML CII with the selected Factur-X runtime. Does not require PDF/A-3 packaging."},"convert_pdfa3_packaging_configured":{"type":"boolean","title":"Convert Pdfa3 Packaging Configured","description":"True when final PDF/A-3 packaging has all static/configured prerequisites: runtime XML, veraPDF URL, and a PDF/A-3 generator configured or detected. This does not imply the generator or veraPDF service is currently operational."},"convert_pdfa3_packaging_available":{"type":"boolean","title":"Convert Pdfa3 Packaging Available","description":"True when /convert can produce verified final PDF/A-3 output with the selected Factur-X runtime, an operational PDF/A-3 generator, and a healthy veraPDF observation."},"convert_pdfa3_dependency":{"type":"string","title":"Convert Pdfa3 Dependency","description":"Machine-readable dependencies for final PDF/A-3 packaging."},"convert_pdfa3_embedding_available":{"type":"boolean","title":"Convert Pdfa3 Embedding Available","description":"True when the fallback XML embedder is available. This is not a guaranteed PDF/A-3 conversion capability."},"convert_pdfa3_embedding_provider":{"type":"string","title":"Convert Pdfa3 Embedding Provider","description":"Provider used for fallback XML embedding, usually facturx_lib."},"convert_pdfa3_generator_available":{"type":"boolean","title":"Convert Pdfa3 Generator Available","description":"True when at least one configured PDF/A-3 generator has a current operational observation."},"convert_pdfa3_generator_providers":{"items":{"type":"string"},"type":"array","title":"Convert Pdfa3 Generator Providers","description":"Operational real PDF/A-3 generator providers."},"convert_pdfa3_generator_configured":{"type":"boolean","title":"Convert Pdfa3 Generator Configured","description":"True when at least one real PDF/A-3 generator is configured or locally detected. This is not an operational availability claim."},"convert_pdfa3_generator_configured_providers":{"items":{"type":"string"},"type":"array","title":"Convert Pdfa3 Generator Configured Providers","description":"Configured or locally detected real PDF/A-3 generator providers. Use convert_pdfa3_generator_providers for operational routing."},"convert_pdfa3_verapdf_configured":{"type":"boolean","title":"Convert Pdfa3 Verapdf Configured","description":"True when VERAPDF_BASE_URL is configured."},"convert_pdfa3_verapdf_health_status":{"type":"string","title":"Convert Pdfa3 Verapdf Health Status","description":"Operational veraPDF status used for PDF/A-3 availability: available, degraded, unknown, or not_configured."},"convert_pdfa3_verapdf_health_checked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Convert Pdfa3 Verapdf Health Checked At","description":"Timestamp of the veraPDF health observation used by /meta, if any."},"convert_pdfa3_verapdf_health_source":{"type":"string","title":"Convert Pdfa3 Verapdf Health Source","description":"Source of the veraPDF health status used by /meta."},"convert_degraded_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Convert Degraded Reason","description":"Machine-readable reason when one convert mode is degraded. Null means endpoint, XML CII, and PDF/A-3 packaging are all available."},"supports_convert":{"type":"boolean","title":"Supports Convert","description":"Deprecated compatibility alias for convert_pdfa3_packaging_available. Use the split convert_endpoint_available, convert_xml_cii_available, and convert_pdfa3_packaging_available fields for precise capability routing.","default":false}},"additionalProperties":true,"type":"object","required":["supports_facturx_runtime_xsd","supports_en16931_compiled_xslt","supports_pdfa_via_verapdf","facturx_runtime_schematron_guaranteed","convert_endpoint_available","convert_xml_cii_available","convert_pdfa3_packaging_configured","convert_pdfa3_packaging_available","convert_pdfa3_dependency","convert_pdfa3_embedding_available","convert_pdfa3_embedding_provider","convert_pdfa3_generator_available","convert_pdfa3_generator_providers","convert_pdfa3_generator_configured","convert_pdfa3_generator_configured_providers","convert_pdfa3_verapdf_configured","convert_pdfa3_verapdf_health_status","convert_pdfa3_verapdf_health_checked_at","convert_pdfa3_verapdf_health_source","convert_degraded_reason"],"title":"CapabilitiesInfo"},"ValidationReadinessSectionResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Layer status. The runtime emits one of the values declared by ``ReadinessStatus`` in ``app/domain/services/product_truth_contract.py``: today the closed set is ``passed`` / ``incomplete`` / ``blocked`` / ``not_run`` / ``not_evaluated`` / ``not_applicable`` / ``unknown`` / ``not_submitted`` / ``accepted_user_declared`` / ``accepted_verified``. ``incomplete`` (france_2026 frCtc only) means the layer carries warning-severity ``advisories`` but no fatal blocker. The OpenAPI typing keeps the field as ``str`` so the engine can introduce a new evidence-bearing value without a breaking schema bump; the contract test ``test_openapi_validation_readiness_examples_match_runtime_status_set`` pins every example to the runtime set. France-first claim policy: ``passed`` MUST be backed by an evaluated stage — see ``docs/VALIDATION_TOPOLOGY.md`` §7."},"blockers":{"items":{"type":"string"},"type":"array","title":"Blockers","description":"Stable rule_id / blocker_id list backing the status. Empty when ``status`` is ``passed`` / ``not_submitted``; a ``not_evaluated`` section may still carry out-of-scope markers (e.g. ``PROFILE_UNKNOWN`` when no Factur-X/CII profile was detected). Always equals ``blockerCount`` in length."},"blockerCount":{"type":"integer","minimum":0.0,"title":"Blockercount","description":"Cached ``len(blockers)`` so SDKs do not have to re-count. Always equal to the length of ``blockers``.","default":0},"advisories":{"items":{"type":"string"},"type":"array","title":"Advisories","description":"Stable rule_id list of NON-blocking advisories from the FR-CTC pack actually executed. Present on the ``frCtc`` layer when its ``status`` is ``incomplete``: the document is exchangeable but not fully conformant and these are the non-conformities to resolve. Omitted entirely when empty (backward-compatible). Distinct from ``blockers``: an advisory is never a fatal block."},"advisoryCount":{"type":"integer","minimum":0.0,"title":"Advisorycount","description":"Cached ``len(advisories)`` so SDKs do not have to re-count. Always equal to the length of ``advisories``. Omitted when zero.","default":0},"evidence":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Evidence","description":"Short evidence token explaining how the status was produced (e.g. ``factur_x_runtime_extensions_not_runtime_observed``, ``pa_lifecycle_not_part_of_validation_target``)."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Human-readable reason for ``not_evaluated`` / ``blocked`` states. Absent when the layer evaluated cleanly."},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"Sub-target of the layer when relevant — e.g. ``pdf_a3`` for ``packaging`` or ``factur_x_runtime_extensions`` for ``facturxProfile``."},"sourcePresent":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Sourcepresent","description":"True only when this readiness layer is backed by an actual source that reached runtime validation. For ``en16931`` this means a submitted XML source was available (direct XML upload or extractible embedded Factur-X XML) and at least one XSD or Schematron stage actually ran on that source; generated XML from native-PDF extraction and skipped placeholder stages do not set this flag."},"diagnosticOnly":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Diagnosticonly","description":"When true, this layer reports diagnostic truth about the submitted source document and must not be converted by clients into a runnable /convert blocker or api_gap by itself."},"diagnosticScope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Diagnosticscope","description":"Scope of a diagnostic-only layer, for example ``submitted_embedded_xml`` when EN16931 was evaluated on the XML embedded in an uploaded PDF while PDF/A-3 packaging remains a separate readiness axis."},"dependsOn":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Dependson","description":"Stable dependency tokens for this layer. France 2026 uses ``target_profile_valid`` here instead of hard-coding ``en16931_base`` so Extended-CTC-FR can fail closed without being over-rejected by an EN16931-strict heuristic."},"targetProfile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Targetprofile","description":"Target profile whose validity gates this layer, for example ``en16931`` for standard EN16931-targeted France checks or ``extended_ctc_fr`` for Extended-CTC-FR. Dependency tokens such as ``target_profile_valid`` live in ``dependsOn``."},"targetProfileValid":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Targetprofilevalid","description":"True only when the target profile was actually evaluated and valid. False means a core/base target-profile defect blocks this layer. Null means the target profile was not evaluated, for example Extended-CTC-FR when its resolver executor is not wired."},"targetProfileValidEvaluated":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Targetprofilevalidevaluated","description":"Whether the engine actually evaluated ``targetProfileValid``."},"baseFailureKind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basefailurekind","description":"Stable dependency failure class when ``targetProfileValid`` is false. Currently emitted value: ``core``. Future Extended-CTC-FR-specific attribution is intentionally not part of the public enum until the executor can emit it."},"candidateValidation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Candidatevalidation","description":"Generated-candidate validation evidence kept separate from submitted-document readiness. When a source PDF has no embedded Factur-X XML, the submitted-source truth is carried separately by ``submittedSourceReadiness`` while generated-candidate evidence can remain visible here."}},"additionalProperties":true,"type":"object","required":["status"],"title":"ValidationReadinessSectionResponse","description":"One readiness layer (``en16931``, ``facturxProfile``,\n``frCtc``, ``paAcceptance``, or ``packaging``).\n\nMirrors ``ValidationReadinessSection`` in\n``app/domain/services/product_truth_contract.py:to_dict``. The\nruntime is authoritative for the value space — this DTO only\npublishes the shape and the camelCase field names.","examples":[{"blockerCount":0,"blockers":[],"evidence":"en16931_base_passed","sourcePresent":true,"status":"passed"},{"blockerCount":0,"blockers":[],"evidence":"factur_x_runtime_extensions_not_runtime_observed","reason":"factur_x_runtime_profile_schematron_not_runtime_observable_for_en16931","status":"not_evaluated","target":"factur_x_runtime_extensions"},{"blockerCount":0,"blockers":[],"evidence":"pa_lifecycle_not_part_of_validation_target","reason":"pa_lifecycle_not_part_of_validation_target","status":"not_submitted","target":"not_submitted"}]},"ConvertAsyncProcessingResultResponse":{"properties":{"status":{"type":"string","enum":["processing"],"const":"processing","title":"Status","description":"The conversion job was accepted and has not completed yet."},"jobId":{"type":"string","minLength":1,"title":"Jobid","description":"Non-empty identifier used to poll the accepted conversion job."}},"additionalProperties":false,"type":"object","required":["status","jobId"],"title":"ConvertAsyncProcessingResultResponse","description":"Strict result payload returned while an async conversion is pending."},"ValidationTargetDocumentEvidenceResponse":{"properties":{"sellerCountry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sellercountry","description":"Seller country evidence extracted from XML or request context (ISO 3166-1 alpha-2)."},"buyerCountry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Buyercountry","description":"Buyer country evidence extracted from XML or request context (ISO 3166-1 alpha-2)."}},"additionalProperties":false,"type":"object","title":"ValidationTargetDocumentEvidenceResponse","description":"Seller/buyer country evidence used to resolve France CTC targeting."},"DraftCandidatePreviewResponse":{"properties":{"kind":{"type":"string","enum":["draft_candidate"],"const":"draft_candidate","title":"Kind","description":"Stable discriminator for a target-preflight draft candidate preview."},"status":{"type":"string","enum":["preview_only"],"const":"preview_only","title":"Status","description":"Preview-only status; this object is never a final conversion artifact."},"basis":{"type":"string","enum":["target_preflight_probe"],"const":"target_preflight_probe","title":"Basis","description":"Evidence basis for the preview: an internal target-preflight dry-run probe."},"exchangeable":{"type":"boolean","enum":[false],"const":false,"title":"Exchangeable","description":"Always false. Clients must not send or archive this preview as an invoice."},"valid":{"type":"boolean","enum":[false],"const":false,"title":"Valid","description":"Always false. Final validity requires a real /convert replay and validation."},"validationStatus":{"type":"string","enum":["not_validated_for_exchange"],"const":"not_validated_for_exchange","title":"Validationstatus","description":"Public validation status for the preview; never reports valid."},"probeValidationStatus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Probevalidationstatus","description":"Internal probe validation status, exposed only as discovery evidence. It does not make the preview valid or exchangeable."},"xmlAvailable":{"type":"boolean","title":"Xmlavailable","description":"Whether the internal probe produced XML; the XML itself is never exposed here."},"xmlSize":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Xmlsize","description":"Size in bytes of the internal probe XML when known."},"requiredInputCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requiredinputcount","description":"Number of required inputs discovered by the corresponding targetPreflight."},"unsupportedBlockerCount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unsupportedblockercount","description":"Number of unsupported blockers in the corresponding targetPreflight."},"reason":{"type":"string","title":"Reason","description":"Human-readable explanation that the preview used synthetic values and must be replayed through final /convert with confirmed business inputs."}},"additionalProperties":false,"type":"object","required":["kind","status","basis","exchangeable","valid","validationStatus","xmlAvailable","reason"],"title":"DraftCandidatePreviewResponse","description":"Non-exchangeable target-preflight candidate preview."},"LinksInfo":{"properties":{"docs":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Docs"},"openapi":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Openapi"},"changelog":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Changelog"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"generated_at":{"type":"string","title":"Generated At"}},"additionalProperties":true,"type":"object","required":["generated_at"],"title":"LinksInfo"},"ValidationEngineInfo":{"properties":{"en16931_cen_runtime":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"En16931 Cen Runtime","description":"Official CEN EN16931 runtime truth, per syntax: UBL production executes CEN 1.3.16; CII production follows FACTURX_RUNTIME_VERSION (not CEN-routed). cen_axis_prepared_version exposes the prepared CEN axis (1.3.16) with cen_axis_source; historic top-level version/selected/default stay on rollback 1.3.15 with source=rollback_until_cii_routed until production_default_flipped is true (public CII also routes CEN 1.3.16). selected/configured vs routed/executable, plus the digest of a live loaded validator when present. execution_status=loaded is the only field claiming a CEN validator was constructed from those bytes. EN16931 only — not Factur-X conformance, not France CTC, not PA acceptance."},"artifacts":{"items":{"$ref":"#/components/schemas/ValidationArtifact"},"type":"array","title":"Artifacts"},"pdfa":{"$ref":"#/components/schemas/PdfaEngineInfo"},"facturx_runtime":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Facturx Runtime","description":"Factur-X runtime artifact version currently executed."},"fr_ctc_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fr Ctc Version","description":"France CTC (FNFE-MPE) pack version *selected/configured* for this process, from FR_CTC_RUNTIME_VERSION or the runtime default. Not a claim that Saxon executed it — see fr_ctc_runtime.enabled / executable / loaded / execution_status."},"fr_ctc_runtime":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Fr Ctc Runtime","description":"France CTC runtime truth: selected/configured vs enabled/executable/loaded. execution_status=loaded only when the orchestrator has a live Flux2 validator; vendored artifacts alone never imply execution."}},"additionalProperties":true,"type":"object","required":["artifacts","pdfa"],"title":"ValidationEngineInfo"},"TargetPreflightContractResponse":{"properties":{"requested":{"type":"string","enum":["en16931","france_2026"],"title":"Requested","description":"Requested validation target for this preflight contract."},"evaluatedTarget":{"anyOf":[{"type":"string","enum":["en16931","france_2026"]},{"type":"null"}],"title":"Evaluatedtarget","description":"Validation target this preflight actually evaluated. Clients key target-specific behaviour on this field, not on requested."},"status":{"type":"string","enum":["complete","incomplete","unsupported","failed"],"title":"Status","description":"Whether the target-aware preflight is complete, incomplete, blocked by unsupported items or failed during proof execution."},"exhaustive":{"type":"boolean","title":"Exhaustive","description":"true only when candidate validation, or an equivalent deterministic proof, has made requiredInputs, beforeTransmissionInputs and unsupportedBlockers exhaustive."},"basis":{"type":"string","enum":["candidate_validation","known_rule_map","source_validation"],"title":"Basis","description":"Evidence basis used to build the preflight contract."},"requiredInputs":{"items":{"$ref":"#/components/schemas/ProductTruthConversionInputResponse"},"type":"array","title":"Requiredinputs","description":"Supported caller inputs required before local Factur-X generation."},"beforeTransmissionInputs":{"items":{"$ref":"#/components/schemas/ProductTruthConversionInputResponse"},"type":"array","title":"Beforetransmissioninputs","description":"Supported inputs that do not block local generation but remain required before France 2026 transmission. Values are replayable from conversionInputRecipe.examplePayload."},"automaticFixes":{"items":{"$ref":"#/components/schemas/ProductTruthConversionInputResponse"},"type":"array","title":"Automaticfixes","description":"Target blockers covered by automatic /convert fixes after the recipe payload is applied."},"unsupportedBlockers":{"items":{"$ref":"#/components/schemas/ProductTruthConversionInputResponse"},"type":"array","title":"Unsupportedblockers","description":"Target blockers not covered by current public /convert inputs or automatic fixes."},"routedInputs":{"items":{"$ref":"#/components/schemas/ProductTruthConversionInputResponse"},"type":"array","title":"Routedinputs","description":"Supported target inputs with their resolved public /convert route paths, such as invoice_patch, seller_context or buyer_context."},"remainingAfterInputsPolicy":{"type":"string","enum":["none_expected","unknown","possible"],"title":"Remainingafterinputspolicy","description":"Policy for blockers after the supported inputs are supplied. unknown/possible means clients must not present guided conversion as complete."},"incompleteReason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Incompletereason","description":"Machine-readable reason when exhaustive=false. Present so clients do not infer a complete checklist from a partial preflight."}},"additionalProperties":true,"type":"object","required":["requested","status","exhaustive","basis","requiredInputs","beforeTransmissionInputs","automaticFixes","unsupportedBlockers","routedInputs","remainingAfterInputsPolicy"],"title":"TargetPreflightContractResponse","description":"France 2026 target-aware dry-run preflight contract."},"ConvertDryRunErrorEnvelopeResponse":{"properties":{"success":{"type":"boolean","enum":[false],"const":false,"title":"Success","description":"Always ``false`` on the dry-run error envelope. Mandatory: callers must emit the marker explicitly."},"request_id":{"type":"string","minLength":1,"title":"Request Id","description":"Non-empty correlation identifier for this dry-run error response. The same value is also returned in the ``X-Request-Id`` header."},"artifactLineage":{"allOf":[{"$ref":"#/components/schemas/CausalArtifactLineageResponse"}],"description":"Canonical source-only or source/candidate causal chain produced from the bytes handled by this dry-run execution."},"causalDecision":{"allOf":[{"$ref":"#/components/schemas/CausalDecisionContractResponse"}],"description":"API-owned decision and repeated-occurrence identity contract."},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"Short scoped target contract for compatibility and dry-run error intent. It preserves requested/executed/status so clients do not infer scope from ``success`` alone; detailed executable truth lives in ``validationReadiness``."},"dry_run":{"type":"boolean","enum":[true],"const":true,"title":"Dry Run","description":"Always ``true`` on the dry-run error envelope. Mandatory: callers must emit the marker explicitly."},"verdict":{"type":"string","enum":["ready","auto_repairable","needs_confirmation","convert_with_inputs","profile_upgrade_required","convert_incomplete","source_correction_required","erp_complete","target_not_evaluated","unsupported"],"title":"Verdict","description":"Dry-run verdict bucket. Closed domain: ``ready``, ``auto_repairable``, ``needs_confirmation``, ``convert_with_inputs``, ``profile_upgrade_required``, ``convert_incomplete``, ``source_correction_required``, ``erp_complete``, ``target_not_evaluated``, ``unsupported``. Mandatory on this variant because the route emits one for every dry-run error. See the success envelope's ``verdict`` description for per-value semantics."},"apiCapability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Apicapability","description":"Legacy capability projection emitted on dry-run error responses. Clients should prefer productTruthModel.generationCapability."},"issues":{"items":{"type":"object"},"type":"array","title":"Issues","description":"Dry-run issue list. Mandatory on this variant — at least one issue is always synthesised when extraction fails so callers see the cause."},"extracted_data":{"type":"null","title":"Extracted Data","description":"Always ``null`` on the dry-run error envelope — no extraction was produced. Mandatory: callers must emit the explicit ``null`` so generated SDKs cannot mistake an absent key for a populated extracted-data block."},"missing_fields":{"items":{"type":"string"},"type":"array","title":"Missing Fields","description":"Business fields the engine could not extract. Mandatory on this variant; may be empty when the engine failed before field detection."},"recoverable_with_invoice_data":{"type":"boolean","title":"Recoverable With Invoice Data","description":"Whether at least one ``erp_must_complete`` issue is present, signalling the caller can repair via ``invoice_data``. Mandatory on this variant."},"requirements":{"items":{"type":"object"},"type":"array","title":"Requirements","description":"Typed Product Truth requirements for this dry-run error."},"fieldProvenance":{"additionalProperties":{"type":"object"},"type":"object","title":"Fieldprovenance","description":"Per-critical-field provenance, present even when extraction failed."},"conflicts":{"items":{"type":"object"},"type":"array","title":"Conflicts","description":"Profile/override conflicts. Empty when no external inputs were resolved."},"validationReadiness":{"allOf":[{"$ref":"#/components/schemas/ValidationReadinessResponse"}],"description":"Five-layer Product Truth readiness contract (en16931, facturxProfile, frCtc, paAcceptance, packaging). Present on the dry-run error envelope so SDKs always see the same shape — see the success envelope above for the per-layer semantics."},"france2026Projection":{"anyOf":[{"$ref":"#/components/schemas/France2026ProjectionResponse"},{"type":"null"}]},"generationReadiness":{"anyOf":[{"$ref":"#/components/schemas/GenerationReadinessResponse"},{"type":"null"}]},"transmissionReadiness":{"anyOf":[{"$ref":"#/components/schemas/TransmissionReadinessResponse"},{"type":"null"}]},"submittedSourceReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Submittedsourcereadiness","description":"Lifecycle readiness for the submitted source artifact only. It separates uploaded PDF/XML source truth from generated-candidate truth: for example, a source PDF without embedded Factur-X XML can have a generated candidate that validates while the submitted source remains not_evaluated for that target. Clients must not treat candidate readiness as source-document readiness."},"candidateValidationReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Candidatevalidationreadiness","description":"Lifecycle readiness for a generated candidate artifact, when a dry-run or scan/convert surface actually generated and validated one. This field is separate from submittedSourceReadiness and from finalGeneratedValidation; it is discovery/repair evidence. Clients must not use it as proof that the submitted source or final deliverable is ready."},"finalGeneratedValidation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Finalgeneratedvalidation","description":"Lifecycle readiness for the final generated deliverable after actual generation and packaging. It is absent/null before final generation and must not be inferred from source validation or candidate validation alone."},"productTruthModel":{"anyOf":[{"$ref":"#/components/schemas/ProductTruthModelResponse"},{"type":"null"}],"description":"Single causal Product Truth model emitted by the API for rendering scan, report, email and conversion surfaces without client-side target heuristics. It separates submitted file/XML truth, generation capability, generated candidate validation, France 2026 applicability/actions, identity verification and PA lifecycle. Clients should render status, counters and CTA capability from this object instead of re-counting issues or inferring state from the requested target name."},"conversionInputRecipe":{"type":"object","title":"Conversioninputrecipe","description":"Product Truth conversion recipe, present even when extraction failed so clients do not infer a fake public conversion action. Includes nonRunnableDecisions when the correct public state is fail-closed rather than /convert."},"convertPreparation":{"type":"object","title":"Convertpreparation","description":"Scanner-facing `/convert` handoff grouped into extracted fields, suggestions, confirmations, user-provided values, editable templates, unsupported API gaps, and non-runnable product decisions."},"nextAction":{"allOf":[{"$ref":"#/components/schemas/ConvertNextActionResponse"}],"description":"Canonical fail-closed dry-run action for this error envelope. Extraction-failure responses still publish it so generated SDKs do not have to special-case a missing action contract."},"diagnostics":{"items":{"type":"object"},"type":"array","title":"Diagnostics","description":"Free-form diagnostic entries surfaced on the dry-run error branch. Mandatory on this variant (the ``ConvertResponse`` parent makes it optional because the success envelope does not emit it)."},"result":{"allOf":[{"$ref":"#/components/schemas/ConvertResultDryRunErrorResponse"}],"description":"Strict result envelope: every locked invariant from :class:`ConvertResultDryRunErrorResponse` (extraction null, empty applied / artifacts, scope label ``\"(no profile applied)\"``, validation_status ``\"error\"``) applies."},"targetPreflight":{"anyOf":[{"$ref":"#/components/schemas/TargetPreflightContractResponse"},{"type":"null"}],"description":"France 2026-only dry-run preflight contract, omitted for ``validation_target=en16931``. France 2026 error responses use it to expose incomplete or unsupported target preflight states without guessing from legacy counters."},"draftCandidate":{"anyOf":[{"$ref":"#/components/schemas/DraftCandidatePreviewResponse"},{"type":"null"}],"description":"Optional non-exchangeable target-preflight preview. It may be present when an extraction-failure response still completed a candidate probe, but it is never a valid/sendable artifact."}},"type":"object","required":["success","request_id","artifactLineage","causalDecision","target","dry_run","verdict","issues","extracted_data","missing_fields","recoverable_with_invoice_data","requirements","fieldProvenance","conflicts","validationReadiness","conversionInputRecipe","convertPreparation","nextAction","diagnostics","result"],"title":"ConvertDryRunErrorEnvelopeResponse","description":"Strict envelope for the dry-run extraction-failure branch.\n\nSibling of :class:`ConvertResponse` for the dry-run error path.\nLocks every top-level marker the route emits so a generated SDK\nsees the error variant as a distinct ``oneOf`` arm at the top\nlevel — not just at the nested ``result`` level.\n\nRequired by Codex review 10: the parent envelope union on\n``ConvertResponse`` was bypassable because the loose ``result``\nunion accepted a success-shape result with a ``ConvertResponse``\nbody wearing dry-run error markers. ``ConvertResponse`` now\nrejects that bypass via a ``model_validator``; this dedicated\nenvelope additionally documents the strict shape in OpenAPI so\nclients can branch on the top-level variant via the ``oneOf``.\n\nLocked top-level markers\n------------------------\n\n* ``success`` is ``Literal[False]`` — the engine did not produce\n  a Factur-X output;\n* ``dry_run`` is ``Literal[True]`` — only emitted on dry-run;\n* ``extracted_data`` is locked to ``None`` — extraction failed;\n* ``diagnostics`` is mandatory (was optional on\n  :class:`ConvertResponse`) — clients always receive the\n  remediation hints carried by this branch;\n* ``result`` is ``ConvertResultDryRunErrorResponse`` (no Union)\n  — every locked-empty / locked-const invariant on the result\n  envelope is therefore re-locked at the parent level."},"PresentationState":{"type":"string","enum":["can_generate_now","unknown"],"title":"PresentationState"},"NonEvaluation":{"properties":{"reason":{"type":"string","title":"Reason"},"profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile"},"profileLayer":{"type":"string","enum":["passed"],"const":"passed","title":"Profilelayer"},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target"},"targetLayer":{"type":"string","enum":["not_run","blocked"],"title":"Targetlayer"}},"type":"object","required":["reason","profileLayer","targetLayer"],"title":"NonEvaluation","description":"Why ``valid`` is false although no rule failed.\n\nThe profile layer passed. The requested target was not evaluated\n(``not_run`` or ``blocked``). Absent when the target was evaluated."},"En16931ExecutionResponse":{"properties":{"profile":{"type":"string","enum":["EN16931"],"const":"EN16931","title":"Profile"},"executed":{"type":"boolean","title":"Executed"},"passed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Passed"},"blockers":{"items":{"type":"string"},"type":"array","title":"Blockers"},"artifactVersion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Artifactversion"}},"type":"object","required":["profile","executed","passed","blockers","artifactVersion"],"title":"En16931ExecutionResponse","description":"Bounded evidence of the submitted source's canonical EN16931 execution."},"RepairChangeCategory":{"type":"string","enum":["correction","normalization","warning"],"title":"RepairChangeCategory","description":"Canonical Product Truth classification for a repair diff item."},"ValidationTargetExecutionResponse":{"properties":{"status":{"type":"string","enum":["skipped"],"const":"skipped","title":"Status","description":"Non-execution status. Currently only `skipped` is emitted."},"reason":{"type":"string","enum":["feature_flag_disabled","artifact_unavailable","runtime_not_implemented","artifact_runtime_error","jurisdiction_not_applicable","not_requested","not_attempted"],"title":"Reason","description":"Stable machine-readable reason for the skipped France CTC execution."}},"additionalProperties":false,"type":"object","required":["status","reason"],"title":"ValidationTargetExecutionResponse","description":"Why a targeted France CTC runtime did not execute."},"ApiErrorEnvelope":{"properties":{"detail":{"$ref":"#/components/schemas/ApiErrorDetail"},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id"}},"additionalProperties":false,"type":"object","required":["detail","request_id"],"title":"ApiErrorEnvelope","description":"Single error shape consumed by SDKs and the web application."},"ValidationTargetPaLifecycleResponse":{"properties":{"target":{"type":"string","enum":["not_submitted"],"const":"not_submitted","title":"Target"},"reason":{"type":"string","enum":["pa_lifecycle_not_part_of_validation_target"],"const":"pa_lifecycle_not_part_of_validation_target","title":"Reason"}},"additionalProperties":false,"type":"object","required":["target","reason"],"title":"ValidationTargetPaLifecycleResponse","description":"PA lifecycle is explicitly out of scope for technical validation."},"ReportDecision":{"properties":{"decisionVersion":{"type":"integer","enum":[1],"const":1,"title":"Decisionversion"},"state":{"anyOf":[{"type":"string","enum":["S1","S2","S3","S4","S5","S6","api_gap","unsupported"]},{"type":"null"}],"title":"State"},"document":{"type":"string","enum":["invoice","credit_note","unknown"],"title":"Document"},"titleKey":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Titlekey"},"subtitleKey":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitlekey"},"primaryAction":{"anyOf":[{"$ref":"#/components/schemas/ReportDecisionAction"},{"type":"null"}]},"secondaryAction":{"anyOf":[{"$ref":"#/components/schemas/ReportDecisionAction"},{"type":"null"}]},"counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Counts"},"readyToTransmit":{"additionalProperties":{"type":"string","enum":["ready","needs_input","blocked","not_evaluated","not_generated"]},"type":"object","title":"Readytotransmit"},"layers":{"items":{"$ref":"#/components/schemas/ReportDecisionLayer"},"type":"array","title":"Layers"},"basis":{"type":"object","title":"Basis"}},"additionalProperties":false,"type":"object","required":["decisionVersion","state","document","titleKey","subtitleKey","primaryAction","secondaryAction","counts","readyToTransmit","layers","basis"],"title":"ReportDecision","description":"S1: the one report decision; surfaces display it and decide nothing (state None = not covered, never guessed)."},"ValidationSummaryResponse":{"properties":{"errorCount":{"type":"integer","minimum":0.0,"title":"Errorcount"},"warningCount":{"type":"integer","minimum":0.0,"title":"Warningcount"}},"type":"object","required":["errorCount","warningCount"],"title":"ValidationSummaryResponse","description":"Aggregated validation counters."},"PdfaEngineInfo":{"properties":{"provider":{"type":"string","title":"Provider"},"configured":{"type":"boolean","title":"Configured"},"health_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Health Status","description":"Operational veraPDF status observed by the runtime health gate: available, degraded, unknown, or not_configured."},"health_checked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Health Checked At","description":"Timestamp of the health observation used by /meta, if any."},"health_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Health Source","description":"Source of the health observation used by /meta."},"version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version"}},"additionalProperties":true,"type":"object","required":["provider","configured"],"title":"PdfaEngineInfo"},"CausalActionInstanceResponse":{"properties":{"actionInstanceId":{"type":"string","pattern":"^fxn_[A-Za-z0-9_-]{43}$","title":"Actioninstanceid"},"decisionId":{"type":"string","pattern":"^fxd_[A-Za-z0-9_-]{43}$","title":"Decisionid"},"subjectIds":{"items":{"type":"string"},"type":"array","title":"Subjectids"}},"additionalProperties":false,"type":"object","required":["actionInstanceId","decisionId","subjectIds"],"title":"CausalActionInstanceResponse"},"ConvertResultDryRunErrorResponse":{"properties":{"durationMs":{"type":"integer","title":"Durationms"},"convertedAt":{"type":"string","title":"Convertedat"},"targetProfile":{"type":"string","title":"Targetprofile"},"conversionSuccessful":{"type":"boolean","enum":[false],"const":false,"title":"Conversionsuccessful","description":"Always ``False`` on this branch — the engine did not produce a Factur-X output."},"xmlSize":{"type":"integer","enum":[0],"const":0,"title":"Xmlsize","description":"Always ``0`` — no XML was emitted."},"xml":{"type":"string","maxLength":0,"title":"Xml","description":"Always the empty string — no XML was emitted. Mandatory: callers must emit the explicit empty string. OpenAPI uses ``maxLength: 0`` (not a single-value enum) so code generators can model this as an empty string constraint."},"extraction":{"type":"null","title":"Extraction","description":"Always ``null`` on the dry-run error branch (no extraction report was produced). Mandatory: the explicit ``null`` must be emitted so generated SDKs cannot mistake an absent key for a populated extraction."},"validation":{"type":"object","title":"Validation","description":"Mirrors :class:`ConvertResultResponse.validation` — the stages metadata still ships so callers can render the diagnostic without branching on the result variant."},"pipeline":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Pipeline","description":"Extraction route selected before a later business-term gate stopped dry-run conversion."},"packagingPerformed":{"type":"boolean","enum":[false],"const":false,"title":"Packagingperformed","description":"Always ``False`` — no PDF/A-3 was packaged. Mandatory: callers must emit the explicit ``false``."},"processedInvoicesCharged":{"type":"integer","enum":[0],"const":0,"title":"Processedinvoicescharged","description":"Always ``0`` — dry-run never consumes quota. Mandatory: callers must emit the explicit ``0``."},"ops":{"type":"integer","enum":[0],"const":0,"title":"Ops","description":"Always ``0`` — no internal operation was emitted. Mandatory: callers must emit the explicit ``0``."},"validationStatus":{"type":"string","enum":["error"],"const":"error","title":"Validationstatus","description":"Always ``\"error\"`` on the dry-run extraction-failure branch. The success-path variant accepts the broader enum (``valid`` | ``invalid`` | ``error``)."},"validationScopeLabel":{"type":"string","enum":["(no profile applied)"],"const":"(no profile applied)","title":"Validationscopelabel","description":"Always ``\"(no profile applied)\"`` on this variant — nothing applied, so no scope label is meaningful. Locked to that sentinel so a future emitter cannot advertise a human-facing scope that contradicts the empty applied / artifacts contract."},"appliedValidationProfiles":{"items":{"type":"string","enum":["facturx_en16931_base","facturx_extended","fr_ctc","extended_ctc_fr","chorus_b2g"]},"type":"array","maxItems":0,"title":"Appliedvalidationprofiles","description":"Always the empty array on this branch — no profile actually executed because extraction failed first. Locked empty (``maxItems: 0``) so the contract cannot claim a run that never happened."},"skippedValidationProfiles":{"items":{"$ref":"#/components/schemas/SkippedValidationProfileResponse"},"type":"array","title":"Skippedvalidationprofiles","description":"Profiles the engine considered but did not execute. Preserved across the success / error variants so AUTO + jurisdiction=FR still surfaces ``fr_ctc`` with its non-execution reason. Mandatory on this variant."},"unsupportedValidationProfiles":{"items":{"$ref":"#/components/schemas/UnsupportedValidationProfileResponse"},"type":"array","title":"Unsupportedvalidationprofiles","description":"Reserved for future contract surface; PR 2's resolver leaves this empty (explicit non-runnable profiles raise HTTP 422 ``validation_profile_unavailable``). Mandatory: the empty array must be emitted explicitly."},"validationArtifacts":{"items":{"$ref":"#/components/schemas/ValidationArtifactResponse"},"type":"array","maxItems":0,"title":"Validationartifacts","description":"Always the empty array on the dry-run error branch — no artifact actually participated in this request. Locked empty (``maxItems: 0``) so a generated client cannot validate an artifact entry on a branch where validation never ran."},"messageType":{"type":"string","enum":["invoice","lifecycle_status_cdar"],"title":"Messagetype","description":"``invoice`` | ``lifecycle_status_cdar``."},"legalDisclaimer":{"type":"string","title":"Legaldisclaimer","description":"Canonical phrase asserting the technical scope of the validation. Surfaced even on the error branch so callers consistently render the API's legal posture."},"validationTarget":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetPolicyPayload"}],"description":"Target policy explanation for the dry-run error branch. No validation ran, but the response still states whether France CTC was requested, derived, skipped, or conflicted."}},"type":"object","required":["durationMs","convertedAt","targetProfile","conversionSuccessful","xmlSize","xml","extraction","validation","packagingPerformed","processedInvoicesCharged","ops","validationStatus","validationScopeLabel","appliedValidationProfiles","skippedValidationProfiles","unsupportedValidationProfiles","validationArtifacts","messageType","legalDisclaimer","validationTarget"],"title":"ConvertResultDryRunErrorResponse","description":"Result envelope for the dry-run extraction-failure branch.\n\nEmitted by ``_format_convert_dry_run_error_response`` when the\nengine could not extract enough data to even attempt validation.\nDistinct from :class:`ConvertResultResponse` so the public schema\ndocuments the reduced shape:\n\n* ``extraction`` is always ``None`` (no extraction was produced);\n* ``conversion_successful`` is locked to ``False``;\n* ``xml_size`` is locked to ``0`` and ``xml`` to the empty string;\n* ``packaging_performed`` / ``processed_invoices_charged`` /\n  ``ops`` are locked to their no-op values;\n* the PR 2 validation profile contract block is **mandatory** —\n  every dry-run error response carries it (``validation_status =\n  \"error\"`` with empty ``applied`` and accurate ``skipped``).\n\nGenerated SDKs reach this shape through\n:class:`ConvertDryRunErrorEnvelopeResponse` — the strict sibling\nenvelope published as the second top-level ``oneOf`` arm on the\noperation 200 response. ``ConvertResponse.result`` is\nintentionally narrowed to :class:`ConvertResultResponse` so the\nsuccess / dry-run-business arm cannot represent the\nextraction-failure shape, and the operation 200 union arms stay\nnon-overlapping (``ConvertResponse |\nConvertDryRunErrorEnvelopeResponse``)."},"ConvertNextActionResponse":{"properties":{"code":{"type":"string","enum":["ready","convert_auto","convert_incomplete","convert_with_inputs","profile_upgrade_required","convert_with_confirmations","source_correction_required","api_gap","out_of_scope","target_not_evaluated"],"title":"Code","description":"Deterministic next action. ``source_correction_required``, ``api_gap`` and ``out_of_scope`` are fail-closed and intentionally omit endpoint/method."},"description":{"type":"string","title":"Description","description":"Human-readable explanation of the action."},"endpoint":{"anyOf":[{"type":"string","enum":["/api/v1/convert"],"const":"/api/v1/convert"},{"type":"null"}],"title":"Endpoint","description":"``/api/v1/convert`` when this dry-run can be followed by a call."},"method":{"anyOf":[{"type":"string","enum":["POST"],"const":"POST"},{"type":"null"}],"title":"Method","description":"``POST`` when an endpoint is available."},"requiresInputs":{"type":"boolean","title":"Requiresinputs","description":"Whether caller-supplied business inputs are still required."},"requiresConfirmation":{"type":"boolean","title":"Requiresconfirmation","description":"Whether same-document suggested values must be confirmed first."},"apiGapCount":{"type":"integer","minimum":0.0,"title":"Apigapcount","description":"Number of unsupported inputs/gaps that block public /convert."},"sourceVerificationCount":{"type":"integer","minimum":0.0,"title":"Sourceverificationcount","description":"Number of present source values that remain non-blocking verification advisories, such as an unverified SIRET/SIREN.","default":0},"advisoryActionCount":{"type":"integer","minimum":0.0,"title":"Advisoryactioncount","description":"Number of non-blocking advisory actions. These never make ``requiresInputs`` true and do not block /convert by themselves.","default":0},"requiredBeforeTransmissionCount":{"type":"integer","minimum":0.0,"title":"Requiredbeforetransmissioncount","description":"Number of non-blocking business inputs that are not needed to run ``/convert`` but must still be supplied before transmission.","default":0},"requiresSourceVerification":{"type":"boolean","title":"Requiressourceverification","description":"True when the document has source values to verify even though no blocking /convert input is required.","default":false},"blockingCorrectionCount":{"type":"integer","minimum":0.0,"title":"Blockingcorrectioncount","description":"Number of blocking source/profile corrections. These fail closed before /convert and must not be counted as non-blocking source verification advisories.","default":0},"generationBasis":{"anyOf":[{"type":"string","enum":["rebuild_submitted_facturx","create_from_source"]},{"type":"null"}],"title":"Generationbasis","description":"Optional. Present only when this action offers a generation: rebuild_submitted_facturx when the uploaded PDF already carries a Factur-X/e-invoice XML, create_from_source otherwise."},"paAcceptanceInferred":{"type":"boolean","enum":[false],"const":false,"title":"Paacceptanceinferred","description":"Always false: PA acceptance is never inferred by dry-run."}},"type":"object","required":["code","description","requiresInputs","requiresConfirmation","apiGapCount","paAcceptanceInferred"],"title":"ConvertNextActionResponse","description":"Canonical dry-run action contract.\n\nRuntime dry-run responses always include ``nextAction`` so clients\ndo not infer a runnable workflow from legacy verdict/counter fields.\nThe field is optional only on the success envelope because real\nconversion responses do not emit dry-run action metadata."},"ValidationTargetEn16931Response":{"properties":{"target":{"type":"string","enum":["base"],"const":"base","title":"Target"},"reason":{"type":"string","enum":["en16931_base_always_runs"],"const":"en16931_base_always_runs","title":"Reason"}},"additionalProperties":false,"type":"object","required":["target","reason"],"title":"ValidationTargetEn16931Response","description":"EN16931 base target branch, which always remains in scope."},"ValidationArtifact":{"properties":{"kind":{"type":"string","title":"Kind","description":"Artefact kind (xsd, schematron, xslt, xsl)"},"path":{"type":"string","title":"Path","description":"Path inside the application package"},"sha256":{"type":"string","title":"Sha256"},"size_bytes":{"type":"integer","title":"Size Bytes"},"version_declared":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version Declared"},"version_detected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version Detected"},"origin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}},"additionalProperties":true,"type":"object","required":["kind","path","sha256","size_bytes"],"title":"ValidationArtifact"},"CausalDecisionSubjectResponse":{"properties":{"subjectId":{"type":"string","pattern":"^fxs_[A-Za-z0-9_-]{43}$","title":"Subjectid"},"artifactId":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$","title":"Artifactid"},"artifactScope":{"type":"string","enum":["causal_execution"],"const":"causal_execution","title":"Artifactscope"},"ruleRef":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ruleref"},"btCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Btcode"},"fieldPath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fieldpath"},"occurrenceAnchor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurrenceanchor"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"blocking":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Blocking"},"severityOwner":{"type":"string","enum":["api"],"const":"api","title":"Severityowner"},"blockingOwner":{"type":"string","enum":["api"],"const":"api","title":"Blockingowner"}},"additionalProperties":false,"type":"object","required":["subjectId","artifactId","artifactScope","severityOwner","blockingOwner"],"title":"CausalDecisionSubjectResponse"},"France2026ProjectionResponse":{"properties":{"version":{"type":"string","enum":["1.0"],"const":"1.0","title":"Version"},"futureRegime":{"$ref":"#/components/schemas/France2026RegimeEvaluationResponse"},"currentRegime":{"$ref":"#/components/schemas/France2026RegimeEvaluationResponse"},"effectiveDates":{"$ref":"#/components/schemas/France2026EffectiveDatesResponse"}},"additionalProperties":false,"type":"object","required":["version","futureRegime","currentRegime","effectiveDates"],"title":"France2026ProjectionResponse"},"GenerationReadinessResponse":{"properties":{"status":{"type":"string","enum":["ready","needs_input","blocked","not_evaluated"],"title":"Status"},"blockingInputCount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Blockinginputcount"},"reason":{"type":"string","title":"Reason"}},"additionalProperties":false,"type":"object","required":["status","blockingInputCount","reason"],"title":"GenerationReadinessResponse"},"ProductTruthModelResponse":{"properties":{"version":{"type":"string","title":"Version"},"artifactId":{"type":"string","title":"Artifactid"},"generationCapability":{"$ref":"#/components/schemas/GenerationCapabilityResponse"}},"additionalProperties":true,"type":"object","required":["version","artifactId","generationCapability"],"title":"ProductTruthModelResponse","description":"Typed envelope for the causal Product Truth model."},"CausalArtifactResponse":{"properties":{"artifactId":{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$","title":"Artifactid","description":"Opaque deterministic identity; never derived from human-readable text."},"artifactRole":{"type":"string","enum":["submitted_source","dry_run_candidate","generated_output"],"title":"Artifactrole"},"parentArtifactId":{"anyOf":[{"type":"string","pattern":"^fxa_[A-Za-z0-9_-]{43}$"},{"type":"null"}],"title":"Parentartifactid"}},"additionalProperties":false,"type":"object","required":["artifactId","artifactRole"],"title":"CausalArtifactResponse"},"ConvertResultResponse":{"properties":{"presentation_state":{"anyOf":[{"$ref":"#/components/schemas/PresentationState"},{"type":"null"}]},"decision_copy_key":{"anyOf":[{"type":"string","enum":["scan_presentation.can_generate_now","scan_presentation.unknown"]},{"type":"null"}],"title":"Decision Copy Key"},"primary_action":{"anyOf":[{"$ref":"#/components/schemas/PresentationAction"},{"type":"null"}]},"remaining_work":{"anyOf":[{"items":{"$ref":"#/components/schemas/PresentationWork"},"type":"array"},{"type":"null"}],"title":"Remaining Work"},"presentation_counts":{"anyOf":[{"$ref":"#/components/schemas/PresentationCounts"},{"type":"null"}]},"reportDecision":{"anyOf":[{"$ref":"#/components/schemas/ReportDecision"},{"type":"null"}]},"durationMs":{"type":"integer","title":"Durationms"},"convertedAt":{"type":"string","title":"Convertedat"},"targetProfile":{"type":"string","title":"Targetprofile"},"conversionSuccessful":{"type":"boolean","title":"Conversionsuccessful"},"xmlSize":{"type":"integer","title":"Xmlsize"},"xml":{"type":"string","title":"Xml","description":"Base64-encoded Factur-X XML when a deliverable is produced"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"vNext status: gold, silver, fail, processing"},"jobId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Jobid","description":"Async job identifier when applicable"},"score":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Score"},"pipeline":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Pipeline"},"fallback":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Fallback"},"timings":{"anyOf":[{"additionalProperties":{"type":"integer"},"type":"object"},{"type":"null"}],"title":"Timings"},"cost":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"number"},{"type":"string"}]},"type":"object"},{"type":"null"}],"title":"Cost"},"proofPack":{"anyOf":[{"$ref":"#/components/schemas/ProofPackResponse"},{"type":"null"}]},"pdf":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pdf","description":"Base64-encoded PDF when a deliverable is produced and ephemeral mode is used"},"pdfSize":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pdfsize","description":"PDF size in bytes when a deliverable is produced and ephemeral mode is used"},"pdfUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pdfurl","description":"Presigned download URL when a deliverable is produced and persistent mode is used"},"extraction":{"$ref":"#/components/schemas/ExtractionReportResponse"},"preparedExecutionRef":{"anyOf":[{"$ref":"#/components/schemas/PreparedExecutionReferenceResponse"},{"type":"null"}],"description":"Identity of the sealed PREPARE decision consumed by this GENERATE. Read extraction method telemetry from that PREPARE response."},"validation":{"type":"object","title":"Validation"},"validationReadiness":{"anyOf":[{"$ref":"#/components/schemas/ValidationReadinessResponse"},{"type":"null"}],"description":"Five-layer Product Truth readiness for the final conversion result. The route injects this inside ``result`` so clients read the canonical verdict next to the converted artifact."},"france2026Projection":{"anyOf":[{"$ref":"#/components/schemas/France2026ProjectionResponse"},{"type":"null"}],"description":"Double-regime France 2026 projection. The latest pinned France standard regime is listed first and remains not_evaluated until its exact artifact actually ran; the current runtime regime remains separate."},"generationReadiness":{"anyOf":[{"$ref":"#/components/schemas/GenerationReadinessResponse"},{"type":"null"}],"description":"Inputs that block local Factur-X generation only."},"transmissionReadiness":{"anyOf":[{"$ref":"#/components/schemas/TransmissionReadinessResponse"},{"type":"null"}],"description":"Inputs required before France 2026 routing/transmission."},"conversionInputRecipe":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Conversioninputrecipe","description":"The same phase-aware input recipe exposed by dry-run, rebuilt from the final generated XML and its validation evidence."},"convertPreparation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Convertpreparation","description":"Final-artifact action view derived from conversionInputRecipe; clients must not reclassify or recount its phase buckets."},"submittedSourceReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Submittedsourcereadiness","description":"Lifecycle readiness for the submitted source artifact only. It separates uploaded PDF/XML source truth from generated-candidate truth: for example, a source PDF without embedded Factur-X XML can have a generated candidate that validates while the submitted source remains not_evaluated for that target. Clients must not treat candidate readiness as source-document readiness."},"candidateValidationReadiness":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Candidatevalidationreadiness","description":"Lifecycle readiness for a generated candidate artifact, when a dry-run or scan/convert surface actually generated and validated one. This field is separate from submittedSourceReadiness and from finalGeneratedValidation; it is discovery/repair evidence. Clients must not use it as proof that the submitted source or final deliverable is ready."},"finalGeneratedValidation":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Finalgeneratedvalidation","description":"Lifecycle readiness for the final generated deliverable after actual generation and packaging. It is absent/null before final generation and must not be inferred from source validation or candidate validation alone."},"packagingPerformed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Packagingperformed","description":"Whether the conversion produced a PDF/A-3 artifact (``False`` for ``mode=xml_only`` and dry-run paths)."},"processedInvoicesCharged":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Processedinvoicescharged","description":"Quota units consumed by this call (0 on dry-run paths)."},"remainingInvoices":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Remaininginvoices","description":"Remaining quota for the caller's billing period."},"ops":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ops","description":"Internal operations counter mirrored on dry-run responses (always 0)."},"enrichment":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Enrichment","description":"SIRENE / company enrichment metadata when the engine augmented the extracted invoice data."},"validationStatus":{"anyOf":[{"type":"string","enum":["valid","invalid","error"]},{"type":"null"}],"title":"Validationstatus","description":"Coarse-grained outcome of the EN16931 base run + every ``applied`` profile combined. Closed enum: ``valid`` | ``invalid`` | ``error``. On the dry-run of a submitted document whose embedded XML is blocked, this reflects the SUBMITTED document (``invalid``), NOT the generated candidate — see ``candidateValidationStatus``."},"candidateValidationStatus":{"anyOf":[{"type":"string","enum":["valid","invalid","error"]},{"type":"null"}],"title":"Candidatevalidationstatus","description":"Dry-run only. When the SUBMITTED document is blocked but the engine can generate a conformant Factur-X candidate, this carries the GENERATED CANDIDATE's validation outcome (closed enum: ``valid`` | ``invalid`` | ``error``), separated from the top-level ``validationStatus`` (which reflects the submitted document). Absent (``None``) outside that submitted-vs-candidate split, so the non-dry-run contract is unaffected."},"validationScopeLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validationscopelabel","description":"Human-readable summary of the profiles actually applied (e.g. ``Factur-X EN16931 base + France CTC FNFE-MPE v1.4.0.04``; the version suffix tracks the live FR CTC runtime selection, including an explicit rollback)."},"appliedValidationProfiles":{"items":{"type":"string","enum":["facturx_en16931_base","facturx_extended","fr_ctc","extended_ctc_fr","chorus_b2g"]},"type":"array","title":"Appliedvalidationprofiles","description":"List of profile identifiers that were actually executed."},"skippedValidationProfiles":{"items":{"$ref":"#/components/schemas/SkippedValidationProfileResponse"},"type":"array","title":"Skippedvalidationprofiles","description":"Profiles the engine considered but did not execute (AUTO derivation could not run today). Each entry pins ``profile`` + ``reason`` so callers can render an honest summary."},"unsupportedValidationProfiles":{"items":{"$ref":"#/components/schemas/UnsupportedValidationProfileResponse"},"type":"array","title":"Unsupportedvalidationprofiles","description":"Reserved for future contract surface (deprecated profiles, plan-gated profiles). PR 2's resolver leaves this empty: an explicit profile that cannot run raises HTTP 422 ``validation_profile_unavailable`` instead."},"validationArtifacts":{"items":{"$ref":"#/components/schemas/ValidationArtifactResponse"},"type":"array","title":"Validationartifacts","description":"Provenance of every Schematron / XSLT pack that participated in validation. Stable across requests for the same engine version (sha256-pinned)."},"messageType":{"anyOf":[{"type":"string","enum":["invoice","lifecycle_status_cdar"]},{"type":"null"}],"title":"Messagetype","description":"``invoice`` | ``lifecycle_status_cdar``."},"legalDisclaimer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Legaldisclaimer","description":"Canonical phrase asserting the technical scope of the validation. The API does NOT promise PA acceptance or fiscal conformance — clients must surface this disclaimer alongside any displayed validation outcome."},"validationTarget":{"anyOf":[{"$ref":"#/components/schemas/ValidationTargetPolicyPayload"},{"type":"null"}],"description":"Explains why France CTC was targeted, skipped, or considered conflicted: explicit profile, request jurisdiction, document seller/buyer country evidence, runtime unavailability, and PA lifecycle separation."}},"type":"object","required":["durationMs","convertedAt","targetProfile","conversionSuccessful","xmlSize","xml","extraction","validation"],"title":"ConvertResultResponse","description":"Convert result in API response format.\n\nGenerated deliverables are gated by the canonical\n``validationReadiness`` verdict for the requested ``validation_target``.\n``conversionSuccessful`` is ``true`` only when the requested target is fully\nverified and the response produced a Factur-X deliverable. Validation-only\nsources such as standalone UBL XML keep ``conversionSuccessful=false`` even\nwhen EN16931 validation is verified. An ``incomplete`` result exposes the\ndeliverable with ``conversionSuccessful=false`` and is never labelled\nconforme.\n\nImplements oneOf constraint when deliverables are exposed: either\n'pdf' or 'pdfUrl' is present, never both.\n\nAttributes:\n    duration_ms: Time taken for conversion in milliseconds.\n    converted_at: ISO timestamp of conversion.\n    target_profile: Target Factur-X profile used.\n    conversion_successful: True only when the requested target was verified\n        and a Factur-X deliverable was produced (false for validation-only\n        sources or an incomplete deliverable).\n    xml_size: Size of emitted Factur-X XML in bytes; ``0`` when no XML\n        deliverable is produced.\n    xml: Base64-encoded Factur-X XML when a deliverable is produced.\n    pdf: Base64-encoded PDF when a deliverable is produced and ephemeral mode is used.\n    pdf_size: Size of PDF in bytes when a deliverable is produced and ephemeral mode is used.\n    pdf_url: Presigned download URL when a deliverable is produced and persistent mode is used.\n    extraction: Extraction report metadata.\n    validation: Validation result details."},"UnsupportedValidationProfileResponse":{"properties":{"profile":{"type":"string","enum":["facturx_en16931_base","facturx_extended","fr_ctc","extended_ctc_fr","chorus_b2g"],"title":"Profile"},"reason":{"type":"string","enum":["feature_flag_disabled","artifact_unavailable","runtime_not_implemented","artifact_runtime_error","jurisdiction_not_applicable","not_requested","not_attempted","source_profile_requires_generated_candidate"],"title":"Reason"}},"type":"object","required":["profile","reason"],"title":"UnsupportedValidationProfileResponse","description":"One ``unsupportedValidationProfiles`` entry. Stays empty in PR 2.\n\nSame closed-enum guarantees as :class:`SkippedValidationProfileResponse`."},"PreparedExecutionReferenceResponse":{"properties":{"scanId":{"type":"string","title":"Scanid"},"decisionId":{"type":"string","title":"Decisionid"}},"additionalProperties":false,"type":"object","required":["scanId","decisionId"],"title":"PreparedExecutionReferenceResponse","description":"PREPARE decision identity; extraction telemetry stays on PREPARE."},"ExecutionReceiptResponse":{"properties":{"status":{"type":"string","enum":["proven","not_proven"],"title":"Status"},"receiptId":{"anyOf":[{"type":"string","pattern":"^fxr_[A-Za-z0-9_-]{43}$"},{"type":"null"}],"title":"Receiptid"},"lineage":{"anyOf":[{"$ref":"#/components/schemas/ArtifactLineageResponse"},{"type":"null"}]},"controls":{"anyOf":[{"items":{"$ref":"#/components/schemas/ControlRecordResponse"},"type":"array"},{"type":"null"}],"title":"Controls"},"generationDecisionId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generationdecisionid"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"owner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner"},"escape":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Escape"}},"additionalProperties":false,"type":"object","required":["status"],"title":"ExecutionReceiptResponse"},"ApiErrorDetail":{"properties":{"error":{"type":"string","minLength":1,"title":"Error"},"message":{"type":"string","minLength":1,"title":"Message"}},"additionalProperties":true,"type":"object","required":["error","message"],"title":"ApiErrorDetail","description":"Stable machine code and human-readable message, plus typed context."},"ValidationArtifactResponse":{"properties":{"id":{"type":"string","title":"Id"},"family":{"type":"string","title":"Family"},"profile":{"type":"string","enum":["facturx_en16931_base","facturx_extended","fr_ctc","extended_ctc_fr","chorus_b2g"],"title":"Profile"},"syntax":{"type":"string","enum":["cii","ubl","cdar"],"title":"Syntax","description":"``cii`` | ``ubl`` | ``cdar``"},"version":{"type":"string","title":"Version"},"sourceAuthority":{"type":"string","title":"Sourceauthority"},"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Sha256","description":"64-character lowercase hex sha256"},"status":{"type":"string","enum":["available","runtime_pending","disabled"],"title":"Status","description":"``available`` | ``runtime_pending`` | ``disabled``"},"executed":{"type":"boolean","title":"Executed","description":"True when this artifact actually participated in validation."}},"type":"object","required":["id","family","profile","syntax","version","sourceAuthority","sha256","status","executed"],"title":"ValidationArtifactResponse","description":"One ``validationArtifacts`` entry — provenance of a Schematron / XSLT\npack that participated in validation.\n\n``profile`` / ``syntax`` / ``status`` are closed enums; ``sha256`` is\na strict 64-char lowercase hex pattern. The pattern shows up in the\nOpenAPI schema so generated clients can validate against it."},"France2026EffectiveDatesResponse":{"properties":{"emission":{"type":"string","enum":["2026-09-01"],"const":"2026-09-01","title":"Emission"},"reception":{"type":"string","enum":["2026-10-01"],"const":"2026-10-01","title":"Reception"}},"additionalProperties":false,"type":"object","required":["emission","reception"],"title":"France2026EffectiveDatesResponse"},"FinalConvertTargetValidationFailureDetailResponse":{"properties":{"error":{"type":"string","enum":["target_validation_failed"],"const":"target_validation_failed","title":"Error","description":"Stable machine error for an executed target validation failure."},"message":{"type":"string","title":"Message","description":"Localized human-readable failure explanation."},"target":{"allOf":[{"$ref":"#/components/schemas/ValidationTargetContractPayload"}],"description":"The executed target contract that failed validation."},"validationRules":{"items":{"type":"string"},"type":"array","title":"Validationrules","description":"Blocking validation rule identifiers that caused the target failure. Warning-only findings are excluded from this causal list."}},"additionalProperties":false,"type":"object","required":["error","message","target"],"title":"FinalConvertTargetValidationFailureDetailResponse","description":"Canonical detail for executed final-convert target failures.\n\nThis branch is not a dry-run and not a non-execution: the target validator\nran, rejected the generated candidate, and the API returned no deliverable.\n``target.not_run_reason`` therefore remains null and the machine-readable\ncause lives here."},"GenerationCapabilityResponse":{"properties":{"status":{"type":"string","enum":["can_generate_now","can_generate_after_required_inputs","can_generate_after_confirmation","generated_file_available","cannot_generate_api_gap","unsupported","not_requested"],"title":"Status"},"tone":{"type":"string","enum":["proven_ok","neutral","requires_action","failed"],"title":"Tone"},"reason":{"type":"string","title":"Reason"},"endpoint":{"anyOf":[{"type":"string","enum":["/api/v1/convert"],"const":"/api/v1/convert"},{"type":"null"}],"title":"Endpoint"},"method":{"anyOf":[{"type":"string","enum":["POST"],"const":"POST"},{"type":"null"}],"title":"Method"},"fileField":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filefield"},"executionKind":{"anyOf":[{"type":"string","enum":["generate","download_generated_file"]},{"type":"null"}],"title":"Executionkind"},"sourcePath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourcepath"},"requiredInputCount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Requiredinputcount"},"confirmationCount":{"type":"integer","minimum":0.0,"title":"Confirmationcount"},"apiGapCount":{"type":"integer","minimum":0.0,"title":"Apigapcount"},"automaticFixCount":{"type":"integer","minimum":0.0,"title":"Automaticfixcount"},"executableWithoutUserInput":{"type":"boolean","title":"Executablewithoutuserinput"}},"additionalProperties":false,"type":"object","required":["status","tone","reason","confirmationCount","apiGapCount","automaticFixCount","executableWithoutUserInput"],"title":"GenerationCapabilityResponse","description":"Typed causal Product Truth generation capability projection."},"ArtifactLineageResponse":{"properties":{"finalPdf":{"$ref":"#/components/schemas/LineageArtifactResponse"},"embeddedXml":{"$ref":"#/components/schemas/LineageArtifactResponse"},"candidateXml":{"anyOf":[{"$ref":"#/components/schemas/LineageArtifactResponse"},{"type":"null"}]},"candidateEmbeddedEqual":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Candidateembeddedequal"},"candidateUnprovenCause":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Candidateunprovencause"}},"additionalProperties":false,"type":"object","required":["finalPdf","embeddedXml"],"title":"ArtifactLineageResponse"},"ProductTruthConversionInputResponse":{"properties":{"fieldPath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fieldpath","description":"Logical invoice field path when the blocker maps to a concrete business field."},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label","description":"Human label for the required input, fix or blocker."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Evidence source, for example candidate_validation, document or user_input."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Product Truth item status such as needs_input, automatic_fix or unsupported."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Why the item is required, automatically handled or unsupported."},"supportedByCurrentApi":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Supportedbycurrentapi","description":"Whether the current public API can complete or handle this item."},"btCode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Btcode"},"ruleRef":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ruleref"},"invoiceDataPath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoicedatapath"},"patchPath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Patchpath"},"requestContextPath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestcontextpath"},"profilePath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profilepath"},"detectedValue":{"anyOf":[{},{"type":"null"}],"title":"Detectedvalue"},"apiGap":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Apigap"},"supportKind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supportkind"},"requiredPhase":{"anyOf":[{"type":"string","enum":["before_generation","before_transmission","optional"]},{"type":"null"}],"title":"Requiredphase","description":"Canonical phase bucket assigned by the API; clients must not reclassify it."},"blocksGeneration":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Blocksgeneration","description":"Whether absence of this input blocks local Factur-X generation."},"blocksTransmission":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Blockstransmission","description":"Whether absence of this input blocks France 2026 transmission readiness."},"sourceRuleRef":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sourceruleref","description":"Normative rule reference used to assign the canonical phase."},"phaseEvidence":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Phaseevidence","description":"Versioned normative evidence for a before-transmission classification."}},"additionalProperties":true,"type":"object","title":"ProductTruthConversionInputResponse","description":"Structured Product Truth input/action item.\n\nThe target preflight contract reuses the same item family for\nrequired caller inputs, automatic fixes and unsupported blockers.\nSome automatic-fix entries are rule-level rather than field-level,\nso field-specific paths are optional while the schema still exposes\nthe stable Product Truth keys generated clients need."},"SkippedValidationProfileResponse":{"properties":{"profile":{"type":"string","enum":["facturx_en16931_base","facturx_extended","fr_ctc","extended_ctc_fr","chorus_b2g"],"title":"Profile"},"reason":{"type":"string","enum":["feature_flag_disabled","artifact_unavailable","runtime_not_implemented","artifact_runtime_error","jurisdiction_not_applicable","not_requested","not_attempted","source_profile_requires_generated_candidate"],"title":"Reason"}},"type":"object","required":["profile","reason"],"title":"SkippedValidationProfileResponse","description":"One ``skippedValidationProfiles`` entry.\n\n``profile`` and ``reason`` are closed enums — invalid values are\nrejected at validation time so the wire payload never carries a\nfree-form string (\"ready_pa\", \"accepted_dgfip\", a typo, …)."},"ReportDecisionLayer":{"properties":{"layer":{"type":"string","enum":["en16931","facturxProfile","frCtc","packaging"],"title":"Layer"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"display":{"type":"string","enum":["passed","fixed_by_generation","to_complete","to_fix_at_source","not_evaluated","out_of_scope"],"title":"Display"}},"additionalProperties":false,"type":"object","required":["layer","display"],"title":"ReportDecisionLayer"},"ReportDecisionAction":{"properties":{"code":{"type":"string","minLength":1,"title":"Code"},"labelKey":{"type":"string","minLength":1,"title":"Labelkey"}},"additionalProperties":false,"type":"object","required":["code","labelKey"],"title":"ReportDecisionAction"},"ControlRecordResponse":{"properties":{"controlId":{"type":"string","minLength":1,"title":"Controlid"},"scope":{"type":"string","enum":["xml","pdf_packaging"],"title":"Scope"},"requested":{"type":"boolean","title":"Requested"},"executionState":{"type":"string","enum":["executed","not_executed","not_applicable"],"title":"Executionstate"},"subjectArtifactId":{"type":"string","pattern":"^fxe_[A-Za-z0-9_-]{43}$","title":"Subjectartifactid"},"contentSha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Contentsha256"},"result":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result"},"cause":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cause"},"owner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner"},"escape":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Escape"}},"additionalProperties":false,"type":"object","required":["controlId","scope","requested","executionState","subjectArtifactId","contentSha256"],"title":"ControlRecordResponse"},"LineageArtifactResponse":{"properties":{"artifactId":{"type":"string","pattern":"^fxe_[A-Za-z0-9_-]{43}$","title":"Artifactid"},"artifactRole":{"type":"string","enum":["candidate_xml","embedded_xml","final_pdf"],"title":"Artifactrole"},"contentSha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Contentsha256"},"parentArtifactId":{"anyOf":[{"type":"string","pattern":"^fxe_[A-Za-z0-9_-]{43}$"},{"type":"null"}],"title":"Parentartifactid"}},"additionalProperties":false,"type":"object","required":["artifactId","artifactRole","contentSha256"],"title":"LineageArtifactResponse"},"France2026RegimeEvaluationResponse":{"properties":{"regimeId":{"type":"string","title":"Regimeid"},"rulesetVersion":{"type":"string","title":"Rulesetversion"},"policyVariant":{"type":"string","title":"Policyvariant"},"status":{"type":"string","enum":["passed","passed_with_advisories","blocked","failed","inconclusive","not_evaluated","not_applicable"],"title":"Status"},"evaluationSubject":{"type":"string","enum":["submitted_source","generated_candidate","unknown"],"title":"Evaluationsubject"},"blockerRefs":{"items":{"type":"string"},"type":"array","title":"Blockerrefs"},"blockerCount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Blockercount"},"advisoryRefs":{"items":{"type":"string"},"type":"array","title":"Advisoryrefs"},"advisoryCount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Advisorycount"},"artifacts":{"items":{"$ref":"#/components/schemas/France2026RulesetArtifactResponse"},"type":"array","title":"Artifacts"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"executionComplete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Executioncomplete"},"ruleEvaluationDiagnostics":{"items":{"$ref":"#/components/schemas/France2026RuleEvaluationDiagnosticResponse"},"type":"array","title":"Ruleevaluationdiagnostics"}},"additionalProperties":false,"type":"object","required":["regimeId","rulesetVersion","policyVariant","status","evaluationSubject","blockerRefs","blockerCount","advisoryRefs","advisoryCount","artifacts","reason"],"title":"France2026RegimeEvaluationResponse"},"ProofPackResponse":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expiresat"}},"type":"object","title":"ProofPackResponse","description":"Proof-pack signed URL metadata for conversion responses."},"ExtractionReportResponse":{"properties":{"sourceType":{"type":"string","enum":["native_text","scan_ocr","hybrid","embedded_xml","xml_upload","prepared_execution"],"title":"Sourcetype"},"pageCount":{"type":"integer","title":"Pagecount"},"pageConfidences":{"anyOf":[{"items":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"number"}]},"type":"object"},"type":"array"},{"type":"null"}],"title":"Pageconfidences"},"overallConfidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Overallconfidence"},"ocrProcessingTimeMs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ocrprocessingtimems"}},"type":"object","required":["sourceType","pageCount"],"title":"ExtractionReportResponse","description":"Extraction report in API response format.\n\nContains the extraction method, or ``prepared_execution`` when GENERATE\nrestores the exact candidate admitted by PREPARE.\n\nAttributes:\n    source_type: How data was extracted (native_text or scan_ocr).\n    page_count: Total number of pages in source PDF.\n    page_confidences: Per-page OCR confidence scores (only for scan_ocr).\n    overall_confidence: Average OCR confidence percentage (only for scan_ocr).\n    ocr_processing_time_ms: Time spent on OCR in milliseconds."},"France2026RuleEvaluationDiagnosticResponse":{"properties":{"ruleId":{"type":"string","minLength":1,"title":"Ruleid"},"technicalCode":{"type":"string","pattern":"^(?:[A-Z]{4}[0-9]{4}|RULE_EVALUATION_ERROR)$","title":"Technicalcode"},"context":{"type":"string","title":"Context"},"test":{"type":"string","title":"Test"},"location":{"type":"string","title":"Location"},"producerOccurrenceRef":{"type":"string","minLength":1,"title":"Produceroccurrenceref"},"evaluationStatus":{"type":"string","enum":["not_evaluated"],"const":"not_evaluated","title":"Evaluationstatus"}},"additionalProperties":false,"type":"object","required":["ruleId","technicalCode","context","test","location","producerOccurrenceRef","evaluationStatus"],"title":"France2026RuleEvaluationDiagnosticResponse"},"France2026RulesetArtifactResponse":{"properties":{"id":{"type":"string","title":"Id"},"version":{"type":"string","title":"Version"},"syntax":{"type":"string","enum":["cii","ubl","cdar"],"title":"Syntax"},"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Sha256"},"sourceAuthority":{"type":"string","title":"Sourceauthority"},"executed":{"type":"boolean","title":"Executed"},"executedSha256":{"anyOf":[{"type":"string","pattern":"^[0-9a-f]{64}$"},{"type":"null"}],"title":"Executedsha256"}},"additionalProperties":false,"type":"object","required":["id","version","syntax","sha256","sourceAuthority","executed"],"title":"France2026RulesetArtifactResponse"}},"securitySchemes":{"PublicApiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Recommended public API key transport for server integrations."},"PublicApiKeyBearer":{"type":"http","scheme":"bearer","bearerFormat":"FacturX API key","description":"Bearer alias for the same public API key."}}},"x-facturx-idempotency-key-contract":{"scope":"authenticated_principal","appliesTo":["/api/v1/convert","/api/v1/repair"],"reuse":"exact_retry_only","crossEndpointReuse":"409 Conflict"},"servers":[{"url":"https://api.facturxapi.com"}]}