{
  "openapi": "3.1.1",
  "info": {
    "title": "Secure PDF Redactor API",
    "version": "1.0.0",
    "summary": "Black out names, numbers or areas in a PDF for real: the text is removed, not just covered.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://securepdfredactor.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Black out names, numbers or areas in a PDF for real: the text is removed, not just covered.",
        "description": "Finds words, phrases, regular expressions or typical personal data (e-mails, phone numbers, IBANs, card numbers) and any rectangles you specify, then rebuilds the affected pages as images with black boxes so the hidden text is truly gone. Optionally re-runs OCR so the rest of the page stays searchable, strips metadata, and proves the result with a text search of the output.\n\nMethodology:\n- Word positions come from Poppler (pdftotext -bbox-layout). Each text line is searched for your words/phrases (spaces may vary), regular expressions and the chosen patterns; every word that overlaps a match gets a black box with 1.5 pt padding. A match that wraps onto the next line is not found as one phrase; the final check reports it.\n- Pages with at least one box are rendered to an image at the chosen DPI, the boxes are painted black into the pixels, and the page is rebuilt from that image. The original text, fonts and vector content of those pages are discarded — covering text with a black rectangle (the common mistake) would leave it copyable.\n- With OCR on, Tesseract re-recognises the remaining visible text of rebuilt pages, so they stay searchable without the redacted words. Pages without hits are copied unchanged (text stays selectable).\n- The document is reassembled with qpdf from scratch, which drops: Document information (title, author, subject, keywords, creator, producer, creation and modification dates); XMP metadata stream; Bookmarks (outline), named destinations and page labels; Attachments (embedded files) and document-level JavaScript; Interactive form (AcroForm) definitions; Page-level metadata and application data (/Metadata, /PieceInfo). With \"Remove comments…\" on, all annotations (comments, links, form widgets) are removed from every page.\n- Verification: the text of the finished PDF is extracted again with pdftotext and every term and pattern is searched; the report lists matches before and after. Only \"0 after\" for every row means the text-level redaction succeeded.\n\nText inside images (scans, screenshots) and text drawn as outlines cannot be found by search; use areas for those, and always review the redacted pages visually before sharing.",
        "tags": [
          "documents"
        ],
        "x-mcp-tool": "secure_pdf_redactor",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SecurePdfRedactorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Redact a name and e-mail addresses",
                  "value": {
                    "terms": [
                      "Alice Smith"
                    ],
                    "presets": [
                      "email"
                    ],
                    "file": {
                      "filename": "contract.pdf",
                      "contentType": "application/pdf",
                      "contentBase64": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUiA1IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSA3IDAgUiA+PiA+PiAvQ29udGVudHMgNCAwIFIgPj4KZW5kb2JqCjQgMCBvYmoKPDwgL0xlbmd0aCAyMTcgPj4Kc3RyZWFtCkJUIC9GMSAyNCBUZiA3MiA3NDIgVGQgKEVtcGxveW1lbnQgY29udHJhY3QpIFRqIEVUCkJUIC9GMSAxNCBUZiA3MiA3MTIgVGQgKEVtcGxveWVlOiBBbGljZSBTbWl0aCkgVGogRVQKQlQgL0YxIDE0IFRmIDcyIDY4MiBUZCAoQ29udGFjdDogYWxpY2Uuc21pdGhAZXhhbXBsZS5jb20pIFRqIEVUCkJUIC9GMSAxNCBUZiA3MiA2NTIgVGQgKFNhbGFyeTogNTIsMDAwIEVVUikgVGogRVQKZW5kc3RyZWFtCmVuZG9iago1IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgNyAwIFIgPj4gPj4gL0NvbnRlbnRzIDYgMCBSID4+CmVuZG9iago2IDAgb2JqCjw8IC9MZW5ndGggMTA0ID4+CnN0cmVhbQpCVCAvRjEgMjQgVGYgNzIgNzQyIFRkIChQYWdlIDIpIFRqIEVUCkJUIC9GMSAxNCBUZiA3MiA3MTIgVGQgKFNpZ25lZCBieSBBbGljZSBTbWl0aCBhbmQgQm9iIEpvbmVzKSBUaiBFVAplbmRzdHJlYW0KZW5kb2JqCjcgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iagp4cmVmCjAgOAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDA2NCAwMDAwMCBuIAowMDAwMDAwMTI3IDAwMDAwIG4gCjAwMDAwMDAyNTMgMDAwMDAgbiAKMDAwMDAwMDUyMSAwMDAwMCBuIAowMDAwMDAwNjQ3IDAwMDAwIG4gCjAwMDAwMDA4MDIgMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSA4IC9Sb290IDEgMCBSID4+CnN0YXJ0eHJlZgo4OTkKJSVFT0YK"
                    }
                  }
                },
                "example2": {
                  "summary": "Black out a fixed area on page 1",
                  "value": {
                    "areas": "1, 72, 160, 300, 30",
                    "ocr": false,
                    "file": {
                      "filename": "contract.pdf",
                      "contentType": "application/pdf",
                      "contentBase64": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFszIDAgUiA1IDAgUl0gL0NvdW50IDIgPj4KZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1BhcmVudCAyIDAgUiAvTWVkaWFCb3ggWzAgMCA1OTUgODQyXSAvUmVzb3VyY2VzIDw8IC9Gb250IDw8IC9GMSA3IDAgUiA+PiA+PiAvQ29udGVudHMgNCAwIFIgPj4KZW5kb2JqCjQgMCBvYmoKPDwgL0xlbmd0aCAyMTcgPj4Kc3RyZWFtCkJUIC9GMSAyNCBUZiA3MiA3NDIgVGQgKEVtcGxveW1lbnQgY29udHJhY3QpIFRqIEVUCkJUIC9GMSAxNCBUZiA3MiA3MTIgVGQgKEVtcGxveWVlOiBBbGljZSBTbWl0aCkgVGogRVQKQlQgL0YxIDE0IFRmIDcyIDY4MiBUZCAoQ29udGFjdDogYWxpY2Uuc21pdGhAZXhhbXBsZS5jb20pIFRqIEVUCkJUIC9GMSAxNCBUZiA3MiA2NTIgVGQgKFNhbGFyeTogNTIsMDAwIEVVUikgVGogRVQKZW5kc3RyZWFtCmVuZG9iago1IDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNTk1IDg0Ml0gL1Jlc291cmNlcyA8PCAvRm9udCA8PCAvRjEgNyAwIFIgPj4gPj4gL0NvbnRlbnRzIDYgMCBSID4+CmVuZG9iago2IDAgb2JqCjw8IC9MZW5ndGggMTA0ID4+CnN0cmVhbQpCVCAvRjEgMjQgVGYgNzIgNzQyIFRkIChQYWdlIDIpIFRqIEVUCkJUIC9GMSAxNCBUZiA3MiA3MTIgVGQgKFNpZ25lZCBieSBBbGljZSBTbWl0aCBhbmQgQm9iIEpvbmVzKSBUaiBFVAplbmRzdHJlYW0KZW5kb2JqCjcgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5cGUxIC9CYXNlRm9udCAvSGVsdmV0aWNhIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nID4+CmVuZG9iagp4cmVmCjAgOAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDA2NCAwMDAwMCBuIAowMDAwMDAwMTI3IDAwMDAwIG4gCjAwMDAwMDAyNTMgMDAwMDAgbiAKMDAwMDAwMDUyMSAwMDAwMCBuIAowMDAwMDAwNjQ3IDAwMDAwIG4gCjAwMDAwMDA4MDIgMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSA4IC9Sb290IDEgMCBSID4+CnN0YXJ0eHJlZgo4OTkKJSVFT0YK"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecurePdfRedactorResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "SecurePdfRedactorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "file": {
            "title": "PDF",
            "description": "Max 100 MB and 500 pages. Processed on our server and deleted; the result can be downloaded for about 2 hours. Upload as {filename, contentType?, contentBase64}. Max 102400 KiB. Accepts .pdf,application/pdf.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "terms": {
            "title": "Words or phrases to redact",
            "description": "One per line, e.g. a name or an account number. Matching ignores upper/lower case unless you turn it on below.",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 200
          },
          "patterns": {
            "title": "Regular expressions (advanced)",
            "description": "One JavaScript regular expression per line, e.g. \\bDE\\d{20}\\b.",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 50
          },
          "presets": {
            "title": "Also find",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "phone",
                "iban",
                "card",
                "date"
              ]
            }
          },
          "caseSensitive": {
            "title": "Match upper/lower case exactly",
            "type": "boolean",
            "default": false
          },
          "areas": {
            "title": "Areas to black out",
            "description": "One per line: page (or \"all\"), x, y, width, height, in points from the top-left corner (72 pt = 1 inch) or in % of the page.",
            "type": "string",
            "maxLength": 20000
          },
          "dpi": {
            "title": "Resolution of redacted pages",
            "description": "Redacted pages become images. 150 DPI is readable; 300 DPI is sharper but larger.",
            "type": "integer",
            "minimum": 72,
            "maximum": 300,
            "default": 150,
            "x-unit": "DPI"
          },
          "ocr": {
            "title": "Make redacted pages searchable again (OCR of the remaining text)",
            "type": "boolean",
            "default": true
          },
          "ocrLanguage": {
            "title": "OCR language",
            "type": "string",
            "enum": [
              "eng",
              "deu"
            ],
            "default": "eng"
          },
          "removeAnnotations": {
            "title": "Remove comments, links and form fields from all pages",
            "type": "boolean",
            "default": true
          },
          "password": {
            "title": "PDF password (only if the file is protected)",
            "description": "Used only to open the file for this conversion; it is written to a private temporary file, never to a command line, and deleted with the job.",
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "file"
        ]
      },
      "SecurePdfRedactorResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "pages",
              "redactedPages",
              "boxes",
              "terms",
              "verified",
              "remainingMatches",
              "ocrApplied",
              "metadataRemoved",
              "outputBytes",
              "artifact"
            ],
            "properties": {
              "pages": {
                "type": "integer"
              },
              "redactedPages": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "boxes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "page",
                    "x",
                    "y",
                    "width",
                    "height",
                    "reason"
                  ],
                  "properties": {
                    "page": {
                      "type": "integer"
                    },
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    },
                    "width": {
                      "type": "number"
                    },
                    "height": {
                      "type": "number"
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              },
              "terms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "term",
                    "matchesBefore",
                    "matchesAfter"
                  ],
                  "properties": {
                    "term": {
                      "type": "string"
                    },
                    "matchesBefore": {
                      "type": "integer"
                    },
                    "matchesAfter": {
                      "type": "integer"
                    }
                  }
                }
              },
              "verified": {
                "type": "boolean",
                "description": "True when no search term or pattern occurs in the text of the output (pdftotext)."
              },
              "remainingMatches": {
                "type": "integer"
              },
              "ocrApplied": {
                "type": "boolean"
              },
              "dpi": {
                "type": "integer"
              },
              "metadataRemoved": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "metadataAfter": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Document-level metadata tags still present according to exiftool (if installed)."
              },
              "outputBytes": {
                "type": "integer"
              },
              "artifact": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              },
              "preview": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string",
                    "description": "Download path on the same site (valid for about 2 hours)."
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}