{
  "openapi": "3.1.0",
  "info": {
    "title": "Ritter Energie Asset Gateway API",
    "version": "1.0.0",
    "description": "OpenAPI specification for the lightweight PHP asset gateway exposing Ritter Energie asset routes, JSON link endpoints and health information backed by CELUM.",
    "contact": {
      "name": "Ritter Energie"
    }
  },
  "servers": [
    {
      "url": "/",
      "description": "Same-origin server"
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "Service and upstream CELUM health checks"
    },
    {
      "name": "Assets",
      "description": "Cached asset file routes and pretty JSON link endpoints"
    },
    {
      "name": "Documentation",
      "description": "Machine-readable API documentation"
    }
  ],
  "paths": {
    "/openapi.json": {
      "get": {
        "tags": [
          "Documentation"
        ],
        "summary": "Get the OpenAPI document",
        "operationId": "getOpenApiDocument",
        "responses": {
          "200": {
            "description": "The OpenAPI JSON document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenApiDocument"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Check service, CELUM and asset cache health",
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "Service, upstream and asset cache health information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/product-images/{articleNumber}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Short alias for the first cached product image large route",
        "operationId": "getProductImageLarge",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArticleNumberPath"
          },
          {
            "$ref": "#/components/parameters/Index"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "308": {
            "$ref": "#/components/responses/CanonicalRedirect"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/product-images/{articleNumber}/links": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get pretty JSON links for all cached product images",
        "operationId": "getProductImageLinks",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArticleNumberPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Pretty product image URLs for every cached result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PrettyImageDirectUrls"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/product-images/{articleNumber}_{variant}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Canonical cached product image thumb or preview route",
        "operationId": "getProductImageVariant",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArticleNumberPath"
          },
          {
            "$ref": "#/components/parameters/ImageVariant"
          },
          {
            "$ref": "#/components/parameters/Index"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "308": {
            "$ref": "#/components/responses/CanonicalRedirect"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/product-downloads/{articleNumber}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Short alias for the first cached product download route",
        "operationId": "getProductDownload",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArticleNumberPath"
          },
          {
            "$ref": "#/components/parameters/DocumentTypes"
          },
          {
            "$ref": "#/components/parameters/Index"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "308": {
            "$ref": "#/components/responses/CanonicalRedirect"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/product-downloads/{articleNumber}/links": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get pretty JSON links for all cached product downloads",
        "operationId": "getProductDownloadLinks",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArticleNumberPath"
          },
          {
            "$ref": "#/components/parameters/DocumentTypes"
          }
        ],
        "responses": {
          "200": {
            "description": "Pretty product download URLs for every cached result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PrettyDownloadDirectUrls"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/category-image/{categoryId}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get the cached category image large route",
        "operationId": "getCategoryImageLarge",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryIdPath"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/category-image/{categoryId}/links": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get pretty JSON links for the cached category image",
        "operationId": "getCategoryImageLinks",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Pretty category image URLs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrettyImageDirectUrls"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/category-image/{categoryId}_{variant}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get the cached category image thumb or preview route",
        "operationId": "getCategoryImageVariant",
        "parameters": [
          {
            "$ref": "#/components/parameters/CategoryIdPath"
          },
          {
            "$ref": "#/components/parameters/ImageVariant"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/brand-image/{brandName}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get the cached brand image large route",
        "operationId": "getBrandImageLarge",
        "parameters": [
          {
            "$ref": "#/components/parameters/BrandNamePath"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/brand-image/{brandName}/links": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get pretty JSON links for the cached brand image",
        "operationId": "getBrandImageLinks",
        "parameters": [
          {
            "$ref": "#/components/parameters/BrandNamePath"
          }
        ],
        "responses": {
          "200": {
            "description": "Pretty brand image URLs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrettyImageDirectUrls"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/brand-image/{brandName}_{variant}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Get the cached brand image thumb or preview route",
        "operationId": "getBrandImageVariant",
        "parameters": [
          {
            "$ref": "#/components/parameters/BrandNamePath"
          },
          {
            "$ref": "#/components/parameters/ImageVariant"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/BinaryFile"
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/AssetNotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "ArticleNumberPath": {
        "name": "articleNumber",
        "in": "path",
        "required": true,
        "description": "Product/article number used to resolve cached product assets.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "CategoryIdPath": {
        "name": "categoryId",
        "in": "path",
        "required": true,
        "description": "External category identifier used to resolve the cached category image.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "BrandNamePath": {
        "name": "brandName",
        "in": "path",
        "required": true,
        "description": "Case-sensitive brand name used to resolve the cached brand image.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "DocumentTypes": {
        "name": "documentTypes",
        "in": "query",
        "required": false,
        "description": "Comma-separated list of CELUM document types. Defaults to the configured environment value when omitted.",
        "schema": {
          "type": "string"
        }
      },
      "Index": {
        "name": "index",
        "in": "query",
        "required": false,
        "description": "1-based index used when a cached request returns multiple assets.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "ImageVariant": {
        "name": "variant",
        "in": "path",
        "required": true,
        "description": "Cached image variant to return.",
        "schema": {
          "type": "string",
          "enum": [
            "thumb",
            "preview"
          ]
        }
      }
    },
    "responses": {
      "ValidationError": {
        "description": "The request is invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "AssetNotFound": {
        "description": "No matching cached asset was found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "InternalServerError": {
        "description": "An unexpected internal error occurred.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "CanonicalRedirect": {
        "description": "Alias route redirected to the canonical indexed route.",
        "headers": {
          "Location": {
            "description": "Canonical target route.",
            "schema": {
              "type": "string"
            }
          }
        }
      },
      "BinaryFile": {
        "description": "Cached binary file content.",
        "content": {
          "application/octet-stream": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/png": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/jpeg": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "image/gif": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      }
    },
    "schemas": {
      "OpenApiDocument": {
        "type": "object",
        "description": "The OpenAPI document served by this application.",
        "additionalProperties": true
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/HealthPayload"
          }
        }
      },
      "HealthPayload": {
        "type": "object",
        "required": [
          "service",
          "celum",
          "authentication",
          "details",
          "assetCache"
        ],
        "properties": {
          "service": {
            "type": "string",
            "example": "ok"
          },
          "celum": {
            "type": "string",
            "example": "ok"
          },
          "authentication": {
            "type": "string",
            "example": "ok"
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "celumReachable": true,
              "celumAuthenticated": true,
              "downloadFormatsAvailable": true
            }
          },
          "assetCache": {
            "$ref": "#/components/schemas/AssetCacheHealth"
          }
        }
      },
      "AssetCacheHealth": {
        "type": "object",
        "required": [
          "status",
          "publicDirectory",
          "publicDirectoryWritable"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "ok"
          },
          "publicDirectory": {
            "type": "string",
            "example": "/app/htdocs/asset-cache"
          },
          "publicDirectoryWritable": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorPayload"
          }
        }
      },
      "ErrorPayload": {
        "type": "object",
        "required": [
          "code",
          "message",
          "details"
        ],
        "properties": {
          "code": {
            "type": "string",
            "example": "validation_error"
          },
          "message": {
            "type": "string",
            "example": "The request is invalid."
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "PrettyImageDirectUrls": {
        "type": "object",
        "required": [
          "large",
          "thumb",
          "preview"
        ],
        "properties": {
          "large": {
            "type": "string",
            "format": "uri"
          },
          "thumb": {
            "type": "string",
            "format": "uri"
          },
          "preview": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "PrettyDownloadDirectUrls": {
        "type": "object",
        "description": "Map with exactly one entry where the key is the original download filename and the value is the pretty direct download URL.",
        "additionalProperties": {
          "type": "string",
          "format": "uri"
        },
        "minProperties": 1
      }
    }
  }
}
