{
  "info": {
    "name": "External API V1",
    "description": "External API V1 collection (v1.14.0, updated 2026-08-24) for active Enterprise subscribers with 100 shared Email/API conversions per month and EUR 0.50 prepaid overage credits. PDF conversion ignores embedded invoice XML by default; use_embedded_xml=true is an explicit opt-in. The collection includes explicit output/download parameters, client reconciliation fields, optional seller master data fields, async PDF, DOCX, TXT, and structured-data convert flows across all public output formats, task-status artifact diagnostics, validation-report retrieval, and error-path probes.\n\nRate limits (defaults, per API key): POST /invoices:convert and POST /invoices:convert-structured 30/min and 500/hour; GET /tasks/{task_id} 10/min and 120/hour; GET /tasks/{task_id}/result 10/min and about 134/hour; GET /tasks/{task_id}/validation-report 10/min and 120/hour. Retry-After, X-RateLimit-Limit-Minute, and X-RateLimit-Limit-Hour are returned on 429 responses only.\n\nPolling: wait about 20 seconds after the accepted 202 before the first status call, then back off (20s, 30s, 45s, 60s, and 60s from there on) and stop on completed or failed. Give up after about 16 minutes; the server fails a task after a 5-minute stall window or a 15-minute hard cap. Tasks and their artifacts are retained for 24 hours after reaching a terminal state, as are idempotency records.\n\nRetry rule: branch on the machine-readable code, and on details.code plus details.retryable for 500 TASK_FAILED, never on the HTTP status alone. Retry 429, 502, 504, 503 with a retryable code, and transient 500s that are not TASK_FAILED or INTERNAL_ARTIFACT_INVARIANT_FAILED. Treat 500 TASK_FAILED as terminal unless details.retryable is true (transient provider failures such as rate limiting, timeouts, and transport errors); recover that case with a new conversion and a new Idempotency-Key rather than re-polling the failed task. A terminally failed conversion does not consume a billing unit.\n\nformat x profile: XRECHNUNG accepts [XRECHNUNG] (default XRECHNUNG); EN16931 accepts [EN16931] (default EN16931); UBL accepts [XRECHNUNG, PEPPOL, EN16931] (default EN16931); CII accepts [XRECHNUNG, EN16931, ZUGFERD_EN16931, ZUGFERD_XRECHNUNG] (default EN16931); ZUGFERD accepts [ZUGFERD_EN16931, ZUGFERD_XRECHNUNG] (default ZUGFERD_EN16931). Profiles are matched case-insensitively; ZUGFERD, FACTURX, FACTUR-X, and FACTUR_X alias ZUGFERD_EN16931, and ZUGFERD-XRECHNUNG aliases ZUGFERD_XRECHNUNG.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://www.invoice-converter.com"
    },
    {
      "key": "api_key",
      "value": ""
    },
    {
      "key": "correlation_id",
      "value": "11111111-1111-4111-8111-111111111111"
    },
    {
      "key": "idempotency_key",
      "value": "idem-convert-001"
    },
    {
      "key": "task_id",
      "value": ""
    },
    {
      "key": "client_reference",
      "value": "ERP-2026-0001"
    },
    {
      "key": "source_system",
      "value": "acme-erp"
    },
    {
      "key": "bad_api_key",
      "value": "icp_invalid_key"
    }
  ],
  "item": [
    {
      "name": "Happy Path",
      "item": [
        {
          "name": "1) Convert Invoice (202)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('convert accepted', function () {",
                  "  pm.expect(pm.response.code).to.eql(202);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('task_id returned', function () {",
                  "  pm.expect(body.task_id).to.be.a('string').and.not.empty;",
                  "});",
                  "if (body.task_id) { pm.collectionVariables.set('task_id', body.task_id); }"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{idempotency_key}}"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "XRECHNUNG"
                },
                {
                  "key": "profile",
                  "type": "text",
                  "value": "PEPPOL",
                  "disabled": true
                },
                {
                  "key": "jurisdiction",
                  "type": "text",
                  "value": "DE",
                  "disabled": true
                },
                {
                  "key": "transaction_scope",
                  "type": "text",
                  "value": "B2G",
                  "disabled": true
                },
                {
                  "key": "delivery_channel",
                  "type": "text",
                  "value": "PEPPOL",
                  "disabled": true
                },
                {
                  "key": "client_reference",
                  "type": "text",
                  "value": "{{client_reference}}"
                },
                {
                  "key": "source_system",
                  "type": "text",
                  "value": "{{source_system}}"
                },
                {
                  "key": "use_embedded_xml",
                  "type": "text",
                  "value": "true",
                  "description": "Optional, default false. Embedded Factur-X, ZUGFeRD, or XRechnung XML inside a PDF is ignored unless this field is explicitly true. Invalid values return 400 INVALID_EMBEDDED_XML_POLICY.",
                  "disabled": true
                },
                {
                  "key": "use_seller_master_data",
                  "type": "text",
                  "value": "true",
                  "description": "Optional. When omitted, the tenant profile default applies; false ignores saved seller defaults for this request. Invalid values return 400 INVALID_SELLER_MASTER_DATA.",
                  "disabled": true
                },
                {
                  "key": "seller_master_data",
                  "type": "text",
                  "value": "{\"business_name\":\"ACME GmbH\",\"street\":\"Musterstr. 1\",\"postal_code\":\"10115\",\"city\":\"Berlin\",\"country\":\"DE\",\"vat_id\":\"DE123456789\"}",
                  "description": "Optional JSON object string with request-scoped seller defaults; used only when use_seller_master_data=true. Every supplied profile value replaces the corresponding extracted seller or payment value; differences create non-blocking warnings. Invalid JSON or unsupported fields return 400 INVALID_SELLER_MASTER_DATA.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            },
            "description": "Uploads a PDF, DOCX, or TXT invoice source document and starts strict async conversion. Embedded invoice XML inside PDFs is ignored by default; use_embedded_xml=true explicitly opts in. Default rate limit: 30/min and 500/hour. The Idempotency-Key must match [A-Za-z0-9._:-]+ with at most 200 characters. The 202 body's message field is informational only (one of 'PDF accepted. Strict conversion started.', 'Invoice document accepted. Strict conversion started.', or 'PDF and structured data accepted. Strict conversion started.') - do not branch on it; branch on status, which is pending (queued, not started yet) or processing. Optional seller master data fields (use_seller_master_data, seller_master_data) let Enterprise tenants apply stored or request-scoped seller defaults for extraction and mapping disambiguation."
          }
        },
        {
          "name": "1b) Convert Structured Invoice (202)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('structured convert accepted', function () {",
                  "  pm.expect(pm.response.code).to.eql(202);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('structured task_id returned', function () {",
                  "  pm.expect(body.task_id).to.be.a('string').and.not.empty;",
                  "});",
                  "if (body.task_id) { pm.collectionVariables.set('task_id', body.task_id); }"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{idempotency_key}}-structured"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "pdf_file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "data_file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "ZUGFERD"
                },
                {
                  "key": "external_invoice_id",
                  "type": "text",
                  "value": "{{client_reference}}"
                },
                {
                  "key": "source_system",
                  "type": "text",
                  "value": "{{source_system}}"
                },
                {
                  "key": "use_seller_master_data",
                  "type": "text",
                  "value": "true",
                  "description": "Optional. When omitted, the tenant profile default applies; false ignores saved seller defaults for this request. Invalid values return 400 INVALID_SELLER_MASTER_DATA.",
                  "disabled": true
                },
                {
                  "key": "seller_master_data",
                  "type": "text",
                  "value": "{\"business_name\":\"ACME GmbH\",\"street\":\"Musterstr. 1\",\"postal_code\":\"10115\",\"city\":\"Berlin\",\"country\":\"DE\",\"vat_id\":\"DE123456789\"}",
                  "description": "Optional JSON object string with request-scoped seller defaults; used only when use_seller_master_data=true. Every supplied profile value replaces the corresponding extracted seller or payment value; differences create non-blocking warnings. Invalid JSON or unsupported fields return 400 INVALID_SELLER_MASTER_DATA.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert-structured",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert-structured"
              ]
            }
          }
        },
        {
          "name": "2) Poll Task Status (200)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}"
              ],
              "query": [
                {
                  "key": "include_validation_report_html",
                  "value": "true",
                  "description": "Optional. Enable only when the polling response should inline sanitized validation report HTML. Values other than true/false return 400 INVALID_QUERY_PARAMETER.",
                  "disabled": true
                }
              ]
            },
            "description": "Polls task state: pending (queued, not started yet), processing, completed, or failed. Default rate limit 10/min and 120/hour, which is the binding constraint. Wait about 20 seconds after the accepted 202 before the first call, then back off (20s, 30s, 45s, 60s, and 60s from there on) and stop on completed or failed; do not poll on a fixed 10-second interval. Completed task payloads may include additive _processing_warnings and _validation_warnings entries with SOURCE_CONTEXT_* rule IDs when source evidence was unavailable, suspect, or truncated; treat these as review signals for exception handling, not failures. Tasks are purged 24 hours after reaching a terminal state and then return 404 TASK_NOT_FOUND."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const body = pm.response.json();",
                  "pm.test('completed status includes result_artifacts diagnostics', function () {",
                  "  if (body.status === 'completed') {",
                  "    pm.expect(body.result_artifacts).to.be.an('object');",
                  "  }",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "3) Fetch Result XML (200 | 202 | 422)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}/result?download=xml",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}",
                "result"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "xml"
                }
              ]
            },
            "description": "Downloads the already-issued XML artifact. Default rate limit 10/min and about 134/hour. A 202 carries the standard error envelope ({\"code\":\"TASK_NOT_READY\",\"message\":\"Strict conversion is still processing. No validated artifact is available yet.\",\"correlation_id\":\"<uuid>\"}), not a file body. On a completed task download=xml is the expected-available artifact for XML-only formats; a 500 INTERNAL_ARTIFACT_INVARIANT_FAILED here is not normal - escalate it with the correlation ID rather than retrying. Successful downloads carry X-Correlation-ID, Content-Disposition, Cache-Control: no-store, X-Artifact-Sha256, X-Validation-Proof-Id, X-Artifact-Proof-Id, X-Artifact-State, X-Validation-State, X-Proof-Status, and X-Validator-Bundle-Id. X-Task-Id is not set on this endpoint."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code === 200) {",
                  "  pm.test('successful XML result returned a file payload', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.match(/application\\/(xml|pdf)|text\\/xml/);",
                  "  });",
                  "  pm.test('artifact proof headers present', function () {",
                  "    pm.expect(pm.response.headers.get('X-Artifact-Sha256')).to.be.a('string').and.not.empty;",
                  "    pm.expect(pm.response.headers.get('X-Validation-Proof-Id')).to.be.a('string').and.not.empty;",
                  "  });",
                  "} else {",
                  "  const body = pm.response.json();",
                  "  pm.test('non-ready or failed result uses documented error code', function () {",
                  "    pm.expect([",
                  "      'TASK_NOT_READY',",
                  "      'VALIDATION_FAILED',",
                  "      'TASK_FAILED',",
                  "      'INTERNAL_ARTIFACT_INVARIANT_FAILED',",
                  "      'AUTHORITATIVE_VALIDATION_UNAVAILABLE',",
                  "      'ARTIFACT_GENERATION_RERUN_REQUIRED',",
                  "      'EXTRACTION_INCOMPLETE_GROUP_FAILURE'",
                  "    ]).to.include(body.code);",
                  "  });",
                  "  pm.test('500 TASK_FAILED is terminal unless details.retryable says otherwise', function () {",
                  "    if (body.code === 'TASK_FAILED') {",
                  "      pm.expect(body.details).to.be.an('object');",
                  "      pm.expect(body.details.code).to.be.a('string');",
                  "    }",
                  "  });",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "4) Fetch Result PDF (200 | 202 | 422)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}/result?download=pdf",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}",
                "result"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "pdf"
                }
              ]
            },
            "description": "For XML-only formats (XRECHNUNG, EN16931, UBL, CII) the PDF rendering is best-effort: download=xml stays authoritative on completed tasks while download=pdf can return an artifact-unavailable error. ZUGFeRD tasks require a PDF source upload; a DOCX/TXT source returns 422 ZUGFERD_SOURCE_PDF_REQUIRED on download=pdf."
          }
        },
        {
          "name": "5) Fetch Validation Report (200 | 202 | 404)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}/validation-report?download=html",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}",
                "validation-report"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "html"
                }
              ]
            },
            "description": "Downloads the validation report tied to the current validated result artifact. Use download=html when available or download=xml for the authoritative KoSIT XML report. Default rate limit 10/min and 120/hour. A 202 carries the standard TASK_NOT_READY error envelope, not a file body. Successful responses carry X-Correlation-ID, Content-Disposition, Cache-Control: no-store, X-Artifact-Sha256, X-Validation-Proof-Id, X-Artifact-Proof-Id, X-Artifact-State, X-Validation-State, X-Proof-Status, X-Validator-Bundle-Id, plus X-Task-Id, X-Validation-Report-Proof-Id, X-Validation-Report-Content-Type, X-Validation-Report-Format, X-Validation-Report-Source, and X-Report-Source-Artifact-Format. On this endpoint the artifact-level diagnostics describe the result artifact the report validates, not the report body: X-Artifact-Sha256 is the SHA-256 of that source artifact and must not be used to checksum the downloaded report, while X-Validation-Report-Proof-Id identifies the proof that supplied the report payload."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('validation report response is expected status', function () {",
                  "  pm.expect([200, 202, 404, 422, 503]).to.include(pm.response.code);",
                  "});",
                  "if (pm.response.code === 200) {",
                  "  pm.test('report proof headers present', function () {",
                  "    pm.expect(pm.response.headers.get('X-Artifact-Sha256')).to.be.a('string').and.not.empty;",
                  "    pm.expect(pm.response.headers.get('X-Validation-Proof-Id')).to.be.a('string').and.not.empty;",
                  "    pm.expect(pm.response.headers.get('X-Validation-Report-Content-Type')).to.be.a('string').and.not.empty;",
                  "  });",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Error Scenarios",
      "description": "Error-path probes for the documented error contract. Since 2026-07-03, strict ZUGFeRD prerequisite failures (missing mandatory fields for hybrid generation) and unresolved blocking_source_conflict extractions fail as 422 VALIDATION_FAILED (data-correction flow) instead of a retryable 503 AUTHORITATIVE_VALIDATION_UNAVAILABLE.\n\nRetry only 429, 502, 504, 503 with a retryable code, and transient 500s that are NOT TASK_FAILED or INTERNAL_ARTIFACT_INVARIANT_FAILED. A 500 is not automatically retryable in this API: 500 TASK_FAILED is a terminal conversion failure whose details.code carries the reason (MULTIPLE_INVOICES_IN_DOCUMENT, NO_INVOICE_DETECTED, INSUFFICIENT_INVOICE_SIGNAL, SCHEMA_PARSE_FAILED, ARTIFACT_PARITY_FAILED, or PROVIDER_ERROR whose retryability follows details.retryable). A terminally failed conversion does not consume a billing unit.\n\nThe 409 class is split by retry semantics: IDEMPOTENCY_IN_PROGRESS is retryable with the SAME key after a short delay (an in-progress claim is reclaimed after 15 minutes), while IDEMPOTENCY_CONFLICT and IDEMPOTENCY_REPLAY_EXPIRED are not retryable and require a new key.\n\nAdditional documented codes not probed here: 400 INVALID_CLIENT_METADATA, 400 INVALID_SELLER_MASTER_DATA, 400 INVALID_QUERY_PARAMETER, 403 API_NOT_ENABLED_FOR_TENANT, 405 METHOD_NOT_ALLOWED (Allow: POST, OPTIONS on conversion paths and Allow: GET, OPTIONS on task paths), 404 TASK_NOT_FOUND / VALIDATION_REPORT_NOT_FOUND, 409 IDEMPOTENCY_REPLAY_EXPIRED, 422 PROFILE_MISMATCH, 422 INVALID_PROFILE (details.allowed_profiles lists the accepted set), 422 UPLOAD_FAILED (invalid jurisdiction, transaction_scope, or delivery_channel), 422 ZUGFERD_SOURCE_PDF_REQUIRED, 422 OUTPUT_PROFILE_CONFLICT, 503 API_CREDIT_SERVICE_UNAVAILABLE, 503 PLAN_TIER_CHECK_FAILED, 503 RATE_LIMIT_SERVICE_UNAVAILABLE, 503 EXTRACTION_INCOMPLETE_GROUP_FAILURE (retry as a NEW conversion; details.failed_groups lists the failed extraction groups), and 502/504 PROXY_ERROR (transport failures, retryable with the same idempotency key).\n\n402 INSUFFICIENT_API_CREDITS has two details shapes: the prepaid shape (remaining, minimum_purchase) and the included-allowance shape (included_remaining, credit_remaining, shortfall, minimum_purchase). Parse on code and read whichever keys are present.",
      "item": [
        {
          "name": "400 Missing Idempotency-Key",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('missing key is rejected', function () {",
                  "  pm.expect(pm.response.code).to.eql(400);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('error code is IDEMPOTENCY_KEY_REQUIRED', function () {",
                  "  pm.expect(body.code).to.eql('IDEMPOTENCY_KEY_REQUIRED');",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "XRECHNUNG"
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            }
          }
        },
        {
          "name": "400 Invalid Idempotency-Key Format",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('invalid key format is rejected', function () {",
                  "  pm.expect(pm.response.code).to.eql(400);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('error code is INVALID_IDEMPOTENCY_KEY', function () {",
                  "  pm.expect(body.code).to.eql('INVALID_IDEMPOTENCY_KEY');",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "invalid key with spaces"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "XRECHNUNG"
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            }
          }
        },
        {
          "name": "401 Invalid API Key",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('invalid api key returns 401', function () {",
                  "  pm.expect(pm.response.code).to.eql(401);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('error code is INVALID_API_KEY or AUTHENTICATION_REQUIRED', function () {",
                  "  pm.expect(['INVALID_API_KEY', 'AUTHENTICATION_REQUIRED']).to.include(body.code);",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{bad_api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/11111111-1111-4111-8111-111111111111",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "11111111-1111-4111-8111-111111111111"
              ]
            }
          }
        },
        {
          "name": "409 Idempotency Conflict (Seed)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "idem-conflict-001"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "XRECHNUNG"
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            }
          }
        },
        {
          "name": "409 Idempotency Conflict (Different Payload)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('conflict or in-progress response', function () {",
                  "  pm.expect(pm.response.code).to.eql(409);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('idempotency error code', function () {",
                  "  pm.expect(['IDEMPOTENCY_CONFLICT', 'IDEMPOTENCY_IN_PROGRESS']).to.include(body.code);",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "idem-conflict-001"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "ZUGFERD"
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            },
            "description": "Reuses the seeded Idempotency-Key with a different payload. IDEMPOTENCY_CONFLICT is NOT retryable - use a new key for a new payload. If the seed request is still being processed you get IDEMPOTENCY_IN_PROGRESS instead, which IS retryable with the same key after a short delay (an in-progress claim is reclaimed after 15 minutes). Once the original task is past its 24-hour retention, a replay returns the non-retryable IDEMPOTENCY_REPLAY_EXPIRED and the conversion must be restarted with a new key."
          }
        },
        {
          "name": "400 Invalid download query",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('invalid download query rejected', function () {",
                  "  pm.expect(pm.response.code).to.eql(400);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('INVALID_DOWNLOAD_FORMAT code', function () {",
                  "  pm.expect(body.code).to.eql('INVALID_DOWNLOAD_FORMAT');",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}/result?download=zip",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}",
                "result"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "zip"
                }
              ]
            }
          }
        },
        {
          "name": "422 Invalid format",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('invalid format is rejected', function () {",
                  "  pm.expect(pm.response.code).to.eql(422);",
                  "});",
                  "var body = pm.response.json();",
                  "pm.test('error code is INVALID_FORMAT', function () {",
                  "  pm.expect(body.code).to.eql('INVALID_FORMAT');",
                  "});"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "idem-invalid-format-001"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "PEPPOL"
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            }
          }
        },
        {
          "name": "413 Payload too large (attach file >20MB)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "idem-large-001"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "format",
                  "type": "text",
                  "value": "XRECHNUNG"
                }
              ]
            },
            "url": {
              "raw": "{{base_url}}/api/v1/invoices:convert",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "invoices:convert"
              ]
            },
            "description": "Attach a local file larger than 20 MB to validate 413 PAYLOAD_TOO_LARGE behavior."
          }
        },
        {
          "name": "429/503 Probe (status endpoint)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}"
              ]
            },
            "description": "Repeat quickly to observe 429 RATE_LIMITED (status bucket default 10/min and 120/hour). Retry-After, X-RateLimit-Limit-Minute, and X-RateLimit-Limit-Hour are returned on 429 responses only, and the body carries details.minute_count, details.hour_count, details.limit_minute, and details.limit_hour. If dependencies are down this can return a retryable 503 such as AUTH_SERVICE_UNAVAILABLE, RATE_LIMIT_SERVICE_UNAVAILABLE, or PLAN_TIER_CHECK_FAILED."
          }
        },
        {
          "name": "500/502/504 Probe (result endpoint)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}"
              },
              {
                "key": "X-Correlation-ID",
                "value": "{{correlation_id}}"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/tasks/{{task_id}}/result?download=xml",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{task_id}}",
                "result"
              ],
              "query": [
                {
                  "key": "download",
                  "value": "xml"
                }
              ]
            },
            "description": "Depending on state and infrastructure this endpoint can return 202, 422, 500, 502, 503, or 504. Retry 502 and 504 PROXY_ERROR (transport failures) and retryable 503 codes; do not retry 500 TASK_FAILED or 500 INTERNAL_ARTIFACT_INVARIANT_FAILED - read details.code on TASK_FAILED and treat an unrecognized value as terminal for that task."
          }
        }
      ]
    }
  ]
}
