{
  "openapi": "3.1.0",
  "info": {
    "title": "EqualDoX REST API",
    "version": "1.0.0",
    "description": "Automated PDF conversion for organisation accounts (https://equaldox.de/api.html). Authenticate with an API key from the dashboard (Konto > API-Schlüssel) as a Bearer token. Polling only. 60 requests per minute per user."
  },
  "servers": [
    {
      "url": "https://equaldox.de"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/api/v1/jobs": {
      "post": {
        "operationId": "createJob",
        "summary": "Upload one PDF and start its conversion (batch class)",
        "parameters": [
          {
            "name": "X-Upload-Filename",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "File name, percent-encoded UTF-8, ending in .pdf"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "pattern": "^[!-~]+$"
            },
            "description": "Repeat the identical request with the same key to get the same job (24 h, per user)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/pdf": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Job created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "job"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "job": {
                      "$ref": "#/components/schemas/Job"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Idempotent replay (header Idempotency-Replayed: true)",
            "headers": {
              "Idempotency-Replayed": {
                "schema": {
                  "const": "true"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "job"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "job": {
                      "$ref": "#/components/schemas/Job"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Replay of a deleted or expired job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "dpa_required, organization_not_active, upload_group_unavailable, page_quota_exceeded, member_page_limit_exceeded, idempotency_key_reused, idempotency_request_in_progress",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "payload_too_large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "unsupported_media_type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "validation_failed (fields.file, fields.filename, fields.idempotency_key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "get": {
        "operationId": "listJobs",
        "summary": "The key's jobs, newest first",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "jobs",
                    "total",
                    "limit",
                    "offset"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "jobs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Job"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "validation_failed (fields.limit, fields.offset)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/jobs/{job_id}": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "operationId": "getJob",
        "summary": "Job status (poll until DONE or FAILED), with a diagnostics summary",
        "responses": {
          "200": {
            "description": "Job",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "job"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "job": {
                      "$ref": "#/components/schemas/Job"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      },
      "delete": {
        "operationId": "deleteJob",
        "summary": "Delete the job and its documents",
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "job_id",
                    "deleted"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "deleted": {
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/jobs/{job_id}/diagnostics": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "operationId": "getJobDiagnostics",
        "summary": "Structured conversion diagnostics (outcome, pages, findings)",
        "responses": {
          "200": {
            "description": "Diagnostics (schema equaldox.api.diagnostics/1)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "job_id",
                    "diagnostics"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "diagnostics": {
                      "$ref": "#/components/schemas/Diagnostics"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/jobs/{job_id}/result": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "operationId": "getJobResult",
        "summary": "Download the converted PDF",
        "responses": {
          "200": {
            "description": "The converted PDF",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "not_found, result_not_available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Charged pages of the key's user in the key's group (website and API)",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "usage"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "usage": {
                      "$ref": "#/components/schemas/Usage"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "validation_failed (fields.from, fields.to)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TermsRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key eqx_..."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "api_key_required, invalid_api_key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TermsRequired": {
        "description": "terms_acceptance_required",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "rate_limited",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "processing_unavailable, storage_unavailable, storage_locked: retry later",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "status",
          "error"
        ],
        "properties": {
          "status": {
            "const": "error"
          },
          "error": {
            "type": "string"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "Job": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "enum": [
              "UPLOADED",
              "PROCESSING",
              "DONE",
              "FAILED"
            ]
          },
          "filename": {
            "type": "string"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "group_id": {
            "type": "string",
            "format": "uuid"
          },
          "submitted_via": {
            "enum": [
              "api",
              "website"
            ]
          },
          "page_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "file_size_bytes": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "result_available": {
            "type": "boolean"
          },
          "error_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "scheduling": {
            "type": "object",
            "properties": {
              "class": {
                "enum": [
                  "batch",
                  "single"
                ]
              },
              "priority": {
                "enum": [
                  "high",
                  "medium",
                  "low",
                  null
                ]
              }
            }
          },
          "billing": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "pages_reserved": {
                "type": "integer"
              },
              "pages_charged": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "settled": {
                "type": "boolean"
              },
              "page_count": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "failed_pages": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "pages_not_charged": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "no_charge_reason": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "links": {
            "type": "object",
            "properties": {
              "self": {
                "type": "string"
              },
              "result": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "diagnostics": {
                "type": "string"
              }
            }
          },
          "diagnostics": {
            "$ref": "#/components/schemas/Diagnostics"
          }
        }
      },
      "Diagnostics": {
        "type": "object",
        "description": "Summary (equaldox.api.diagnostics-summary/1) on GET /jobs/{id}, full view (equaldox.api.diagnostics/1) on /diagnostics; see the documentation",
        "properties": {
          "schema": {
            "type": "string"
          },
          "outcome": {
            "type": "object",
            "properties": {
              "state": {
                "enum": [
                  "pending",
                  "checking",
                  "succeeded",
                  "succeeded_with_warnings",
                  "review_required",
                  "failed"
                ]
              },
              "level": {
                "enum": [
                  "ready",
                  "processed",
                  "corrected",
                  "warnings",
                  "review_required",
                  null
                ]
              },
              "source": {
                "enum": [
                  "inspection",
                  "validation",
                  "status"
                ]
              },
              "final": {
                "type": "boolean"
              }
            }
          },
          "failure": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "error_code": {
                "type": "string"
              },
              "retryable": {
                "type": "boolean"
              },
              "action": {
                "enum": [
                  "retry_later",
                  "fix_input",
                  "contact_support",
                  "resubmit"
                ]
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "pages": {
            "type": "object",
            "properties": {
              "total": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "converted": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "failed": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "with_validation_findings": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "with_inspection_findings": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "validation": {
            "type": [
              "object",
              "null"
            ]
          },
          "inspection": {
            "type": "object"
          },
          "billing": {
            "type": [
              "object",
              "null"
            ]
          },
          "findings": {
            "type": "object",
            "description": "full view only: errors / warnings / notes, each {total, items, truncated}"
          }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "period": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date"
              },
              "to": {
                "type": "string",
                "format": "date"
              },
              "timezone": {
                "const": "Europe/Berlin"
              }
            }
          },
          "scope": {
            "type": "object"
          },
          "pages_charged": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "website": {
                "type": "integer"
              },
              "api": {
                "type": "integer"
              }
            }
          },
          "jobs_settled": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "website": {
                "type": "integer"
              },
              "api": {
                "type": "integer"
              }
            }
          },
          "pages_reserved_open": {
            "type": "integer"
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "website": {
                  "type": "integer"
                },
                "api": {
                  "type": "integer"
                }
              }
            }
          },
          "allowance": {
            "type": [
              "object",
              "null"
            ]
          },
          "organization": {
            "type": [
              "object",
              "null"
            ]
          }
        }
      }
    }
  }
}
