{
  "openapi": "3.1.0",
  "info": {
    "title": "Remediate API",
    "version": "1.0.0",
    "description": "Check PDFs for accessibility and fix them. `validate` checks a PDF against the PDF/UA standard (PDF/UA-1 or PDF/UA-2) and lists each problem with how to fix it by hand. `remediate` fixes the PDF: it marks up the headings, paragraphs, lists and tables, puts everything in reading order, sets the title and language, and fixes fonts so every word can be read aloud. Claude writes the image descriptions and decides what screen readers should skip. You don't need to answer anything. After that you can correct any image description, and we fix the PDF again.\n\nEvery call works in one org. Send an org API key as `Authorization: Bearer rmd_live_…`. Errors look like `{\"error\": {\"code\", \"message\"}}`, and the codes don't change.\n\nThere's no free tier: an org needs a plan, or calls answer 402 `subscription_required`. Fixing a file counts its pages once a month, however many times you fix it. Checking doesn't use any pages. It has a monthly safety limit; failed checks don't count towards it.",
    "contact": {
      "url": "https://remediate.now"
    }
  },
  "servers": [
    {
      "url": "https://api.remediate.now"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "PDF"
    },
    {
      "name": "Documents"
    },
    {
      "name": "Org"
    }
  ],
  "paths": {
    "/v1/orgs/{org}/validate": {
      "post": {
        "summary": "Validate a PDF",
        "description": "Checks the file against PDF/UA-1 or PDF/UA-2 (veraPDF rule ids). Not billed; a monthly safety cap applies.",
        "tags": [
          "PDF"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Validation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "profile",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "ua1",
                "ua2"
              ]
            },
            "description": "Default: the part the file claims."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/pdf": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/remediate": {
      "post": {
        "summary": "Remediate a PDF (not kept)",
        "description": "Remediates the PDF and returns it, without keeping it. Claude (AI) makes the judgment calls unless the org has turned it off. Headers Remediate-Compliant, Remediate-Remaining-Rules and Remediate-Changes summarise the result; format=json returns the report with the PDF as base64. Alt text is never invented: figures get it from the file, a caption, image metadata or Claude looking at the image.",
        "tags": [
          "PDF"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RemediationJson"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pdf",
                "json"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/pdf": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/documents": {
      "get": {
        "summary": "List documents",
        "description": "Newest first; `next` continues the list. Documents are deleted 30 days after upload.",
        "tags": [
          "Documents"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ]
      },
      "post": {
        "summary": "Upload and validate a document",
        "description": "Validates the PDF and keeps it for 30 days. Not billed; then POST its remediate link.",
        "tags": [
          "Documents"
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/pdf": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/documents/{doc}": {
      "get": {
        "summary": "A document: its validation and, once remediated, its report",
        "description": "",
        "tags": [
          "Documents"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "delete": {
        "summary": "Delete a document now",
        "description": "",
        "tags": [
          "Documents"
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "patch": {
        "summary": "Correct image descriptions, and fix the PDF again",
        "description": "Saves a person's description for each figure (or marks it decoration only) and runs the remediation again with them, so they win over Claude's on this run and every later one. Answers 202 with status `remediating`; poll the document as after `remediate`. With wait=true, answers 200 when done. The figure ids are in the report's `figures`. The file's pages count once a month, so doing this in the same billing period uses no more pages. 409 `not_remediated` until the document has been fixed, 409 `already_remediating` while it runs.",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "wait",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FigureEdit"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "202": {
            "description": "Started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/orgs/{org}/documents/{doc}/original": {
      "get": {
        "summary": "Download the original",
        "description": "",
        "tags": [
          "Documents"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/orgs/{org}/documents/{doc}/remediated": {
      "get": {
        "summary": "Download the accessible PDF",
        "description": "409 not_remediated until the document has been remediated.",
        "tags": [
          "Documents"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/me": {
      "get": {
        "summary": "Who is calling",
        "description": "The key (its org, role and scopes) or the signed-in user.",
        "tags": [
          "Org"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/orgs/{org}": {
      "get": {
        "summary": "The org",
        "description": "Plan and billing state included.",
        "tags": [
          "Org"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          }
        ]
      }
    },
    "/v1/orgs/{org}/billing": {
      "get": {
        "summary": "Plan and usage this period",
        "description": "Pages used against the plan's allowance.",
        "tags": [
          "Org"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          }
        ]
      }
    },
    "/v1/plans": {
      "get": {
        "summary": "Plans",
        "tags": [
          "Org"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/documents/{doc}/remediate": {
      "post": {
        "summary": "Remediate a document",
        "description": "Starts remediation and answers 202 with status `remediating`; poll the document until it is `remediated` (or `failed`, with `error`). With wait=true, answers 200 when done. Billed by page once it succeeds, once per file per billing period. Running it again replaces the result.",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "wait",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "202": {
            "description": "Started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/orgs/{org}/documents/{doc}/figures/{fig}/image": {
      "get": {
        "summary": "A figure as it appears on its page",
        "description": "A PNG crop of the figure from the original file, for someone writing its description. 404 `figure_not_found` when the report has no such figure, or no place for it on a page.",
        "tags": [
          "Documents"
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^org_[0-7][0-9a-hjkmnp-tv-z]{25}$",
              "example": "org_01k8a4z7m2q9x3v5c6b7n8p9rt"
            },
            "description": "Your org's id, `org_` and 26 letters and digits. It's on the API keys page."
          },
          {
            "name": "doc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "fig",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "f1"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The crop",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An org API key (rmd_live_…) or an OAuth access token from an MCP client."
      }
    },
    "responses": {
      "Error": {
        "description": "An error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "missing_key",
                  "invalid_key",
                  "rate_limited",
                  "org_not_found",
                  "forbidden",
                  "missing_scope",
                  "subscription_required",
                  "payment_failed",
                  "org_suspended",
                  "quota_exceeded",
                  "not_pdf",
                  "unreadable_pdf",
                  "too_many_pages",
                  "file_too_large",
                  "invalid_profile",
                  "invalid_format",
                  "invalid_json",
                  "invalid_multipart",
                  "document_not_found",
                  "timeout",
                  "internal",
                  "invalid_body",
                  "already_remediating",
                  "not_remediated",
                  "invalid_figures",
                  "figure_not_found"
                ]
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "Figure": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "page": {
            "type": [
              "integer",
              "null"
            ]
          },
          "bbox": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "number"
            }
          },
          "alt": {
            "type": [
              "string",
              "null"
            ]
          },
          "alt_source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "existing",
              "supplied",
              "caption",
              "metadata",
              "provider",
              "ai",
              null
            ],
            "description": "Where the description came from. `supplied`: a person's, sent with PATCH (also when they marked it decoration). `ai`: Claude's (also when Claude found it decorative)."
          },
          "decorative": {
            "type": "boolean"
          }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "profile": {
            "type": "string"
          },
          "compliant": {
            "type": "boolean"
          },
          "violations_before": {
            "type": "integer"
          },
          "violations_after": {
            "type": "integer"
          },
          "issues_before": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "issues_after": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            },
            "description": "Still failing; empty when it passes."
          },
          "changes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Change"
            }
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "lang": {
            "type": [
              "string",
              "null"
            ]
          },
          "figures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Figure"
            }
          },
          "outline": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RemediationJson": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Report"
          },
          {
            "type": "object",
            "properties": {
              "pages": {
                "type": "integer"
              },
              "pdf_base64": {
                "type": "string"
              }
            }
          }
        ]
      },
      "Validation": {
        "type": "object",
        "properties": {
          "profile": {
            "type": "string"
          },
          "compliant": {
            "type": "boolean"
          },
          "failed_rules": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "violations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rule": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "rule_set": {
            "type": "string"
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            },
            "description": "One per failed rule, in plain language."
          }
        }
      },
      "Document": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "sha256": {
            "type": "string"
          },
          "bytes": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "validated",
              "remediating",
              "remediated",
              "failed"
            ]
          },
          "issues_found": {
            "type": [
              "integer",
              "null"
            ]
          },
          "issues_remaining": {
            "type": [
              "integer",
              "null"
            ]
          },
          "compliant": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "lang": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_by": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "links": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "validation": {
            "$ref": "#/components/schemas/Validation"
          },
          "report": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Report"
              },
              {
                "type": "null"
              }
            ]
          },
          "counted_this_period": {
            "type": "boolean",
            "description": "Only on GET of one document. True when its pages already count this billing period, so fixing it again uses no more."
          },
          "counted_at": {
            "type": ["string", "null"],
            "format": "date-time",
            "description": "Only on GET of one document. When a successful fix last counted its pages, in any billing period; null if never."
          }
        }
      },
      "DocumentList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Document"
            }
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          }
        }
      },
      "Issue": {
        "type": "object",
        "properties": {
          "rule": {
            "type": "string",
            "example": "7.3-t01"
          },
          "title": {
            "type": "string",
            "example": "Images have no description"
          },
          "message": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "wcag": {
            "type": "string"
          },
          "how_to_fix": {
            "type": "string",
            "description": "How to fix it by hand (Acrobat Pro), if remediation could not."
          }
        }
      },
      "Change": {
        "type": "object",
        "properties": {
          "area": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "by": {
            "type": "string",
            "enum": [
              "engine",
              "claude",
              "person"
            ],
            "description": "Who made the call: the engine's rules, Claude, or a person (an image description sent with PATCH)."
          }
        }
      },
      "FigureEdit": {
        "type": "object",
        "required": [
          "figures"
        ],
        "properties": {
          "figures": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "required": [
                    "id",
                    "alt"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "example": "f1",
                      "description": "A figure id from the report's `figures`."
                    },
                    "alt": {
                      "type": "string",
                      "maxLength": 2000,
                      "description": "The description a screen reader reads out."
                    }
                  }
                },
                {
                  "type": "object",
                  "required": [
                    "id",
                    "decorative"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "decorative": {
                      "const": true,
                      "description": "Decoration only: screen readers skip it."
                    }
                  }
                }
              ]
            }
          }
        },
        "example": {
          "figures": [
            {
              "id": "f1",
              "alt": "Bar chart of library visits: 41,200 in 2023, 46,900 in 2024 and 52,800 in 2025."
            },
            {
              "id": "f3",
              "decorative": true
            }
          ]
        }
      }
    }
  }
}
