{
  "openapi": "3.1.0",
  "info": {
    "title": "Invoice-Converter External API V1",
    "version": "1.0.0",
    "description": "Headless partner API for converting PDF invoices to XRechnung, ZUGFeRD, and other European e-invoicing formats."
  },
  "servers": [
    {
      "url": "https://invoice-converter.com",
      "description": "Single host for both test and live API keys"
    }
  ],
  "security": [
    {
      "HTTPBearer": []
    }
  ],
  "paths": {
    "/api/v1/invoices:convert": {
      "post": {
        "summary": "Convert a PDF invoice to structured e-invoicing format",
        "operationId": "convertInvoiceV1",
        "tags": [
          "Invoices"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/XCorrelationIdHeader"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ConvertInvoiceRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted — conversion started asynchronously",
            "headers": {
              "X-Correlation-ID": {
                "$ref": "#/components/headers/XCorrelationId"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConvertAcceptedResponse"
                },
                "examples": {
                  "accepted": {
                    "value": {
                      "task_id": "550e8400-e29b-41d4-a716-446655440000",
                      "status": "pending",
                      "message": "PDF accepted. Conversion started.",
                      "filename": "invoice.pdf",
                      "file_size": 245832,
                      "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/tasks/{task_id}": {
      "get": {
        "summary": "Poll task status",
        "operationId": "getTaskStatusV1",
        "tags": [
          "Tasks"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TaskIdPath"
          },
          {
            "$ref": "#/components/parameters/XCorrelationIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Task status retrieved",
            "headers": {
              "X-Correlation-ID": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskStatusResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/TaskStatusFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/tasks/{task_id}/result": {
      "get": {
        "summary": "Download conversion result",
        "operationId": "getTaskResultV1",
        "tags": [
          "Tasks"
        ],
        "description": "Returns the generated file directly. Content-Type is `application/xml` for XML-based formats (XRECHNUNG, UBL, CII, EN16931) or `application/pdf` for ZUGFeRD/Factur-X. If validation fails, the endpoint returns `422 VALIDATION_FAILED` with structured details and no file content.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TaskIdPath"
          },
          {
            "$ref": "#/components/parameters/XCorrelationIdHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Generated file (XML or PDF)",
            "headers": {
              "X-Correlation-ID": {
                "$ref": "#/components/headers/XCorrelationId"
              },
              "Content-Disposition": {
                "description": "Attachment filename, e.g. `attachment; filename=\"invoice.xml\"`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "202": {
            "$ref": "#/components/responses/TaskNotReady"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/TaskResultFailed"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "HTTPBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key"
      }
    },
    "parameters": {
      "XCorrelationIdHeader": {
        "name": "X-Correlation-ID",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "Optional correlation ID for end-to-end request tracing. A UUID is generated automatically if omitted."
      },
      "IdempotencyKeyHeader": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        "description": "Optional idempotency key for safe retries. If omitted, the proxy generates one automatically for write endpoints."
      },
      "TaskIdPath": {
        "name": "task_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "description": "Task UUID returned by the convert endpoint."
      }
    },
    "headers": {
      "XCorrelationId": {
        "description": "Correlation ID for end-to-end request tracing. Use this value when contacting support.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying after a 429.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "XRateLimitLimitMinute": {
        "description": "Per-key minute quota.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "XRateLimitLimitHour": {
        "description": "Per-key hour quota.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "IdempotencyReplayed": {
        "description": "Present and set to `true` when the response is a cached replay of a previous identical request.",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "badRequest": {
                "value": {
                  "code": "BAD_REQUEST",
                  "message": "Invalid JSON body",
                  "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication failed",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          },
          "WWW-Authenticate": {
            "schema": {
              "type": "string",
              "example": "Bearer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Conflict": {
        "description": "Idempotency conflict or request already in progress",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Request payload exceeds limits",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "X-RateLimit-Limit-Minute": {
            "$ref": "#/components/headers/XRateLimitLimitMinute"
          },
          "X-RateLimit-Limit-Hour": {
            "$ref": "#/components/headers/XRateLimitLimitHour"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "code": "RATE_LIMITED",
              "message": "Rate limit exceeded",
              "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
              "details": {
                "minute_count": 30,
                "hour_count": 120,
                "limit_minute": 30,
                "limit_hour": 500
              }
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Dependency unavailable (auth or rate-limit service)",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "TaskNotReady": {
        "description": "Task exists but conversion is still in progress — poll again after a short delay",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "code": "TASK_NOT_READY",
              "message": "Conversion in progress, result not ready yet",
              "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
            }
          }
        }
      },
      "TaskStatusFailed": {
        "description": "Task not found or status could not be retrieved",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "TaskResultFailed": {
        "description": "Task not found or result could not be retrieved",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "Blocking validation errors prevent file delivery",
        "headers": {
          "X-Correlation-ID": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "example": {
              "code": "VALIDATION_FAILED",
              "message": "Validation failed",
              "correlation_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
              "details": [
                {
                  "field": "BuyerReference",
                  "rule_id": "BR-DE-15",
                  "severity": "error",
                  "source": "task-result-download",
                  "suggestion": "Provide Leitweg-ID / BuyerReference."
                }
              ]
            }
          }
        }
      }
    },
    "schemas": {
      "ConvertInvoiceRequest": {
        "type": "object",
        "required": [
          "file"
        ],
        "properties": {
          "file": {
            "type": "string",
            "format": "binary",
            "description": "PDF invoice file to convert."
          },
          "format": {
            "type": "string",
            "enum": [
              "XRECHNUNG",
              "ZUGFERD",
              "EN16931",
              "UBL",
              "CII"
            ],
            "default": "XRECHNUNG",
            "description": "Target output format. Defaults to XRECHNUNG if omitted or invalid."
          }
        }
      },
      "ConvertAcceptedResponse": {
        "type": "object",
        "required": [
          "task_id",
          "status",
          "correlation_id"
        ],
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique task identifier. Use this to poll status and fetch results."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing"
            ],
            "description": "Initial task status. Always `pending` or `processing` on creation."
          },
          "message": {
            "type": "string",
            "description": "Human-readable confirmation message."
          },
          "filename": {
            "type": [
              "string",
              "null"
            ],
            "description": "Original uploaded filename."
          },
          "file_size": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Uploaded file size in bytes."
          },
          "correlation_id": {
            "type": "string",
            "format": "uuid",
            "description": "Request trace ID. Include this value when contacting support."
          }
        },
        "additionalProperties": true
      },
      "TaskStatusResponse": {
        "type": "object",
        "required": [
          "task_id",
          "status",
          "correlation_id"
        ],
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid",
            "description": "Task identifier."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ],
            "description": "Current processing status. `pending` = queued, `processing` = actively converting, `completed` = result ready, `failed` = conversion failed."
          },
          "correlation_id": {
            "type": "string",
            "format": "uuid",
            "description": "Request trace ID."
          }
        },
        "additionalProperties": true
      },
      "ValidationDetail": {
        "type": "object",
        "description": "Structured validation finding with rule reference and remediation suggestion.",
        "properties": {
          "field": {
            "type": [
              "string",
              "null"
            ],
            "description": "Invoice field that triggered the finding."
          },
          "rule_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Validation rule identifier, e.g. `BR-DE-15`, `BT-1`."
          },
          "severity": {
            "type": [
              "string",
              "null"
            ],
            "description": "Finding severity: `error` or `warning`."
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "description": "Validation source: `en16931`, `schematron`, `preflight`, or `kosit`."
          },
          "suggestion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Suggested fix for the issue."
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable description of the finding."
          }
        },
        "additionalProperties": true
      },
      "ErrorEnvelope": {
        "type": "object",
        "description": "Standard error response. All errors follow this shape.",
        "required": [
          "code",
          "message",
          "correlation_id"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable error code, e.g. `RATE_LIMITED`, `INVALID_UPLOAD`."
          },
          "message": {
            "type": "string",
            "description": "Human-readable error description."
          },
          "correlation_id": {
            "type": "string",
            "format": "uuid",
            "description": "Request trace ID. Include when contacting support."
          },
          "details": {
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ValidationDetail"
                }
              },
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Additional structured details. For validation errors, this is an array of `ValidationDetail` objects."
          }
        },
        "additionalProperties": true
      }
    }
  }
