{
  "openapi": "3.1.0",
  "info": {
    "title": "Aiden DocLens API",
    "version": "1.1.0",
    "description": "Standalone asynchronous document processing. Technical success does not imply quality approval."
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "security": [
    {
      "appKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "appKey": {
        "type": "http",
        "scheme": "bearer"
      },
      "adminBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Aparte DocLens-beheersleutel. Geen app-key of gatewaykey."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "code",
          "request_id"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "recovery": {
            "$ref": "#/components/schemas/HttpRecovery"
          },
          "existing_job_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "status_url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Job": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "dossier_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "partial",
              "failed",
              "interrupted"
            ]
          },
          "progress": {
            "type": "object",
            "description": "phase, documents_total/completed, gateway_calls_total/completed; unknown totals omitted"
          },
          "error_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "result_url": {
            "type": "string"
          },
          "recovery": {
            "$ref": "#/components/schemas/ProcessingRecovery"
          },
          "retry_of_job_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "processing_limits": {
            "type": "object",
            "properties": {
              "max_pdf_pages": {
                "type": "integer"
              },
              "max_dossier_pages": {
                "type": "integer"
              },
              "max_qwen_requests": {
                "type": "integer"
              },
              "settings_revision": {
                "type": "integer"
              }
            },
            "description": "Vastgelegde limieten voor deze job; herverwerking krijgt actuele limieten. Oudere resultaten kunnen dit veld missen."
          }
        },
        "required": [
          "recovery",
          "retry_of_job_id"
        ]
      },
      "Result": {
        "type": "object",
        "required": [
          "api_version",
          "schema_version",
          "dossier_id",
          "job_id",
          "quality_status",
          "documents",
          "chunks",
          "interpretations",
          "recovery",
          "retry_of_job_id"
        ],
        "properties": {
          "api_version": {
            "const": "v1"
          },
          "schema_version": {
            "type": "string"
          },
          "dossier_id": {
            "type": "string",
            "format": "uuid"
          },
          "job_id": {
            "type": "string",
            "format": "uuid"
          },
          "quality_status": {
            "const": "requires_human_review"
          },
          "documents": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "chunks": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "interpretations": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "reading_checks": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "artifacts": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "recovery": {
            "$ref": "#/components/schemas/ProcessingRecovery"
          },
          "retry_of_job_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "processing_limits": {
            "type": "object",
            "properties": {
              "max_pdf_pages": {
                "type": "integer"
              },
              "max_dossier_pages": {
                "type": "integer"
              },
              "max_qwen_requests": {
                "type": "integer"
              },
              "settings_revision": {
                "type": "integer"
              }
            },
            "description": "Vastgelegde limieten voor deze job; herverwerking krijgt actuele limieten. Oudere resultaten kunnen dit veld missen."
          }
        }
      },
      "ProcessingFault": {
        "type": "object",
        "required": [
          "code",
          "message",
          "stage",
          "document_id",
          "retryable",
          "action"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "stage": {
            "type": "string"
          },
          "document_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "retryable": {
            "type": "boolean"
          },
          "action": {
            "type": "string"
          }
        }
      },
      "DocumentRecovery": {
        "type": "object",
        "required": [
          "document_id",
          "filename",
          "status",
          "expected_pages",
          "processed_pages",
          "missing_pages",
          "errors"
        ],
        "properties": {
          "document_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "filename": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "enum": [
              "complete",
              "partial",
              "failed"
            ]
          },
          "expected_pages": {
            "type": [
              "integer",
              "null"
            ]
          },
          "processed_pages": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "missing_pages": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "integer"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProcessingFault"
            }
          }
        }
      },
      "RetryAdvice": {
        "type": "object",
        "required": [
          "allowed",
          "action",
          "retry_after_seconds",
          "url",
          "existing_job_id",
          "scope",
          "automatic"
        ],
        "properties": {
          "allowed": {
            "type": "boolean"
          },
          "action": {
            "enum": [
              "poll_status",
              "use_result",
              "retry_job",
              "replace_input_new_dossier",
              "contact_administrator",
              "follow_existing_job"
            ]
          },
          "retry_after_seconds": {
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          },
          "existing_job_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "scope": {
            "const": "all_documents"
          },
          "automatic": {
            "const": false
          }
        }
      },
      "ProcessingRecovery": {
        "type": "object",
        "required": [
          "contract_version",
          "terminal",
          "outcome",
          "result_available",
          "extraction_status",
          "analysis_status",
          "documents",
          "errors",
          "retry"
        ],
        "properties": {
          "contract_version": {
            "const": "1.0"
          },
          "terminal": {
            "type": "boolean"
          },
          "outcome": {
            "enum": [
              "queued",
              "running",
              "complete",
              "partial",
              "failed",
              "interrupted"
            ]
          },
          "result_available": {
            "type": "boolean"
          },
          "extraction_status": {
            "enum": [
              "not_started",
              "in_progress",
              "complete",
              "partial",
              "failed",
              "unknown"
            ]
          },
          "analysis_status": {
            "enum": [
              "not_requested",
              "not_started",
              "complete",
              "incomplete",
              "unknown"
            ]
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentRecovery"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProcessingFault"
            }
          },
          "retry": {
            "$ref": "#/components/schemas/RetryAdvice"
          }
        }
      },
      "HttpRecovery": {
        "type": "object",
        "required": [
          "message",
          "retryable",
          "retry_after_seconds",
          "action",
          "preserve_idempotency_key"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "retryable": {
            "type": "boolean"
          },
          "retry_after_seconds": {
            "type": [
              "integer",
              "null"
            ]
          },
          "action": {
            "type": "string"
          },
          "preserve_idempotency_key": {
            "const": true
          }
        }
      }
    }
  },
  "paths": {
    "/v1/dossiers": {
      "post": {
        "summary": "Create dossier",
        "operationId": "post__v1_dossiers",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "external_reference": {
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/dossiers/{id}": {
      "get": {
        "summary": "Get own dossier, documents and jobs",
        "operationId": "get__v1_dossiers_id",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/dossiers/{id}/documents": {
      "post": {
        "summary": "Upload one file",
        "operationId": "post__v1_dossiers_id_documents",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/dossiers/{id}/jobs": {
      "post": {
        "summary": "Seal dossier and queue job",
        "operationId": "post__v1_dossiers_id_jobs",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "use_gateway": {
                    "type": "boolean",
                    "default": false
                  },
                  "retry_of_job_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "Optional explicit failed parent. Same dossier and gateway mode required; one successor per parent."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/jobs/{id}": {
      "get": {
        "summary": "Poll status and actual progress counters",
        "operationId": "get__v1_jobs_id",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/jobs/{id}/result": {
      "get": {
        "summary": "Get result; 409 while unavailable",
        "operationId": "get__v1_jobs_id_result",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Result"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/jobs/{id}/artifacts/{artifactId}": {
      "get": {
        "summary": "Download authorized derived file",
        "operationId": "get__v1_jobs_id_artifacts_artifactId",
        "responses": {
          "200": {
            "description": "Artifact attachment",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request rejected; stable error code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "artifactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/admin/api/settings": {
      "get": {
        "tags": [
          "Beheer"
        ],
        "summary": "Lees toelating, Qwen-capaciteit en limieten voor nieuwe jobs",
        "security": [
          {
            "adminBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Huidige instellingen, revision en updated_at"
          },
          "401": {
            "description": "Geen geldige beheersleutel"
          },
          "503": {
            "description": "Beheer niet geconfigureerd of database niet beschikbaar"
          }
        }
      },
      "put": {
        "tags": [
          "Beheer"
        ],
        "summary": "Wijzig capaciteit en limieten; paginalimieten en budget gelden voor nieuwe jobs",
        "security": [
          {
            "adminBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "processing_enabled",
                  "gateway_enabled",
                  "revision"
                ],
                "properties": {
                  "processing_enabled": {
                    "type": "boolean"
                  },
                  "gateway_enabled": {
                    "type": "boolean"
                  },
                  "revision": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1
                  },
                  "gateway_max_inflight": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 16,
                    "description": "Gedeeld door alle workers. Standaard 2; weglaten behoudt de huidige waarde. Lopende requests worden niet afgebroken bij verlagen."
                  },
                  "max_pdf_pages": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 500,
                    "description": "Standaard 50. Weglaten behoudt huidige waarde. Wordt bij jobaanmaak vastgelegd; bestaande jobs veranderen niet."
                  },
                  "max_dossier_pages": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2000,
                    "description": "Standaard 100. Weglaten behoudt huidige waarde. Wordt bij jobaanmaak vastgelegd; bestaande jobs veranderen niet."
                  },
                  "max_qwen_requests": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "description": "Standaard 1000. Weglaten behoudt huidige waarde. Wordt bij jobaanmaak vastgelegd; bestaande jobs veranderen niet."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Opgeslagen instellingen met nieuwe revision en updated_at"
          },
          "400": {
            "description": "INVALID_PROCESSING_LIMITS, PDF_LIMIT_EXCEEDS_DOSSIER_LIMIT of INVALID_GATEWAY_CAPACITY; transactie wordt niet opgeslagen."
          },
          "401": {
            "description": "Geen geldige beheersleutel"
          },
          "409": {
            "description": "SETTINGS_CONFLICT: lees opnieuw voordat je opslaat"
          },
          "503": {
            "description": "Beheer of database niet beschikbaar"
          }
        }
      }
    },
    "/admin/api/clients": {
      "get": {
        "tags": [
          "Beheer"
        ],
        "summary": "DocLens-apps met sleutel-ID’s, registratie- en intrektijd; nooit sleutelwaarden of hashes",
        "security": [
          {
            "adminBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "clients met keys per app"
          },
          "401": {
            "description": "Beheersleutel vereist"
          }
        }
      },
      "post": {
        "tags": [
          "Beheer"
        ],
        "summary": "Nieuwe app en eerste sleutel aanmaken",
        "security": [
          {
            "adminBearer": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "name",
                  "operation_id"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  },
                  "operation_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Nieuwe sleutel: api_key wordt uitsluitend in deze response teruggegeven; bewaar hem direct. Alleen een hash wordt opgeslagen."
          },
          "400": {
            "description": "Ongeldige of ontbrekende gegevens"
          },
          "401": {
            "description": "Beheersleutel vereist"
          },
          "404": {
            "description": "App bestaat niet"
          },
          "409": {
            "description": "APP_NAME_EXISTS, APP_DISABLED of KEY_ALREADY_ISSUED. Een herhaalde operation_id geeft nooit opnieuw een sleutel."
          }
        }
      }
    },
    "/admin/api/clients/{clientId}/keys": {
      "post": {
        "tags": [
          "Beheer"
        ],
        "summary": "Extra sleutel uitgeven voor dezelfde app en bestaande dossiers",
        "security": [
          {
            "adminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "operation_id"
                ],
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Nieuwe sleutel: api_key wordt uitsluitend in deze response teruggegeven; bewaar hem direct. Alleen een hash wordt opgeslagen."
          },
          "400": {
            "description": "Ongeldige of ontbrekende gegevens"
          },
          "401": {
            "description": "Beheersleutel vereist"
          },
          "404": {
            "description": "App bestaat niet"
          },
          "409": {
            "description": "APP_NAME_EXISTS, APP_DISABLED of KEY_ALREADY_ISSUED. Een herhaalde operation_id geeft nooit opnieuw een sleutel."
          }
        }
      }
    },
    "/admin/api/clients/{clientId}/keys/{keyId}/revoke": {
      "post": {
        "tags": [
          "Beheer"
        ],
        "summary": "Sleutel definitief intrekken; dossiers en andere sleutels blijven behouden",
        "security": [
          {
            "adminBearer": []
          }
        ],
        "parameters": [
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Ingetrokken (ook bij herhaling). Nieuwe aanvragen met de sleutel krijgen 401; al geautoriseerde aanvragen en jobs kunnen afronden."
          },
          "401": {
            "description": "Beheersleutel vereist"
          },
          "404": {
            "description": "Sleutel hoort niet bij deze app of bestaat niet"
          }
        }
      }
    },
    "/v1/jobs/{id}/retry": {
      "post": {
        "summary": "Retry a recoverable terminal job using its saved dossier and gateway mode",
        "description": "Requires a fresh Idempotency-Key. Replay the same key after transport errors. A different key for the same parent returns 409 RETRY_ALREADY_CREATED with existing_job_id/status_url, even after completion. No new upload. All documents are reprocessed; AI usage may be billed again. Interrupted or non-retryable jobs are rejected.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Durable successor accepted or idempotently replayed"
          },
          "401": {
            "description": "Invalid app key"
          },
          "404": {
            "description": "Job not owned or absent"
          },
          "409": {
            "description": "Retry not allowed, already created, active dossier or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Processing paused or temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/service/limits": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "Publieke actuele limieten voor nieuwe jobs",
        "security": [],
        "responses": {
          "200": {
            "description": "max_pdf_pages, max_dossier_pages, max_qwen_requests, gateway_max_inflight en revision"
          },
          "503": {
            "description": "Database niet beschikbaar"
          }
        }
      }
    }
  }
}
