# Anonymize document (single-step)

> `POST /job/add/workflow` · Section: Document AI — Anonymization · PaperOffice AI API, release `R20261020.1635`.

`POST https://api.paperoffice.ai/latest/job/add/workflow`

## Overview

One-shot anonymize via template=document_anonymize — detect PII and return anonymized_pdf without HITL. Supports scenario (default gdpr_disclosure; legacy gdpr_auskunft accepted), whitelist, custom_redact, custom_instructions, model, redact_mode (blackout | pseudonymize; pseudonymize requires model=ultra and returns detected_pii.pseudonym_mapping for the controller).

**Parameters:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `template` | string | No | Must be document_anonymize (detect + redact + PDF in one workflow). (default: "document_anonymize") |
| `file` | string | One of (`file`, `pofid`) | PDF or image to anonymize (multipart file) |
| `pofid` | string | One of (`file`, `pofid`) | Or existing DMS POFID (default: "") |
| `redact_categories` | string | No | all / none / CSV category list (default: "all") |
| `whitelist` | string | No | Terms that must NEVER be redacted (e.g. your own company). Separate entries by line break, comma or semicolon; entries match whole words only. A whitelist entry overrides custom_redact only for exactly the same text. (default: "") |
| `custom_redact` | string | No | Terms that must ALWAYS be redacted. Separate entries by line break, semicolon or comma; a comma between two digits stays part of the term (e.g. "18,5 %", "1,000"). Matching is substring-based and ignores case and accents; the whole line or table cell containing the term is redacted (if the same line also contains a whitelist text, only the term itself). (default: "") |
| `custom_instructions` | string | No | Free-text AI policy (default: "") |
| `scenario` | string | No | Redaction policy scenario (default gdpr_disclosure). Scenarios: gdpr_disclosure, external_sharing, public_publication, court_proceedings, whistleblower, internal_audit, medical_records, anonymous_application, hr_personnel_file, research, financial_data, contact_data, custom. Controls visibility floors (e.g. GDPR subject-access whitelist vs external sharing). Legacy internal keys (gdpr_auskunft, externe_weitergabe, oeffentliche_publikation, gerichtsverfahren, whistleblower_hinschg, interne_revision, medizinische_unterlagen, anonyme_bewerbung, personalakte_hr, forschung_wissenschaft, finanzdaten, kontaktdaten, benutzerdefiniert) are still accepted. (allowed: gdpr_disclosure, external_sharing, public_publication, court_proceedings, whistleblower, internal_audit, medical_records, anonymous_application, hr_personnel_file, research, financial_data, contact_data, custom, gdpr_auskunft, externe_weitergabe, oeffentliche_publikation, gerichtsverfahren, whistleblower_hinschg, interne_revision, medizinische_unterlagen, anonyme_bewerbung, personalakte_hr, forschung_wissenschaft, finanzdaten, kontaktdaten, benutzerdefiniert) (default: "gdpr_disclosure") |
| `model` | string | Yes | Required. Anonymize model tier: basic / premium / ultra — list price per page 300 / 500 / 900 credits, multiplied by the processing_lane factor. Without model the request is rejected with 400 MODEL_REQUIRED before billing; unknown values with 400 INVALID_MODEL. (allowed: basic, premium, ultra) |
| `redact_mode` | string | No | blackout (default): black boxes. pseudonymize: identifiers (names, contacts, IBAN/BIC, IDs, birth dates/places, addresses, companies) are replaced by consistent fictitious values so the document stays readable for external chat; Art. 9/criminal/credential data and job titles stay black; amounts stay visible. Requires model=ultra. Not available for whistleblower, court_proceedings, public_publication and anonymous_application (400 REDACT_MODE_LOCKED). Result adds detected_pii.redact_mode, detected_pii.pseudonym_meta and detected_pii.pseudonym_mapping (original -> replacement, for the controller only, never inside the PDF). (allowed: blackout, pseudonymize) (default: "blackout") |
| `priority` | integer | No | Queue priority (1–900). Omit = plan default. 900 = sync when capacity allows. |
| `client_wait` | boolean | No | Connection hold: true (default) = API holds this HTTP request while the job runs, up to the dynamic pipeline timeout (priority, pages, pipeline type; minimum about 20s, infrastructure cap about 295s). Returns the finished result when ready, or HTTP 202 with job_id and poll_url if the hold is exceeded. false = immediate job_id. |
| `async_only` | boolean | No | Same as client_wait=false: immediate job_id — poll GET /job/get/{job_id}. (default: false) |

## Required alternatives

Provide **at least one** of: `file` **or** `pofid`.

**Request body:** `multipart/form-data` — upload via field `file`, `file_1`, or `files` **or** pass `pofid` in the form body. Runtime accepts `file`, `files`, `file_1`, `file_2`, …. The parameter table lists `file_1` and `pofid` as **one of** when both exist. **Exception:** JSON `files` URL arrays are **not** supported on `/job/add/workflow` (unlike most `/job/add/{pipeline}` endpoints). Do not send `application/json` with a `files` array.

## Responses

Returns JSON with `status: "success"`; key fields: `job_id` or inline **`result`**. After poll, workflow/IDP payload stays in **`result`** (not `job_result`). When `idp_collection=invoice`: `pages_idp` / `pages_aiocr` with `_supplier_name`, `_total_amount`. Always read `result ?? job_result`. Optional `_billing` and `processing_time`. Errors: HTTP 4xx/5xx with `status: "error"`, `code`, and `message`.

## Connection hold & polling

- **Default (`client_wait` omitted or `true`):** The API holds **this HTTP connection** while the job runs, up to the **dynamic pipeline timeout** (priority, pages, pipeline type; minimum about 20s, infrastructure cap about 295s). Returns the finished result when ready.
- **Hold exceeded:** If the job is not finished in time → **HTTP 202** with `job_id`, `poll_url`, `max_wait_seconds`, and `client_wait: false`. The job **continues in the background** — poll `GET /job/get/{job_id}` every 5–10 seconds.
- **Immediate poll mode:** `client_wait=false` or `async_only=true` → `job_id` immediately (about 100ms), then poll as above.

**Response fields:** `client_wait` (boolean) — whether this response used connection hold; `max_wait_seconds` — actual hold duration attempted.

**Completed payload key:** After polling, OCR pipelines return the payload in `job_result`; workflow/IDP (`POST /job/add/workflow`) return it in `result`. Always read `result ?? job_result`. See **Job result schema**.

**Note:** Prefer `processing_lane` Start-SLA for wait-to-start / job price — see collection guide **Start-SLA (`processing_lane`) — wait-to-start**. Legacy `priority` is compat only.

## Essentials (all endpoints)

- **Base URL:** `https://api.paperoffice.ai/latest` · **Auth:** `Authorization: Bearer po_sk_…` or `po_ut_…` (server-side only); browser code uses `po_pk_…` with an allowlisted `Origin`. No Bearer at all on a product API returns HTTP 403 `TIER_RESTRICTED`.
- **Errors:** HTTP 4xx/5xx with `status: "error"`, `code` and `message`. Retry 429 (`Retry-After`) and 5xx with exponential backoff; do not retry validation errors.
- **Jobs:** `client_wait=true` (default) holds the connection. HTTP 202 means the job is still running — poll `GET /job/get/{job_id}` every 5–10 s until `job_status` is `completed`, then read `result ?? job_result`. `processing_lane` sets the Start-SLA; legacy `priority` is not part of the public contract.
- **Billing:** every billable product call costs at least 5 credits; read `_billing.job.credits_billed` on billed responses.
- **Mutations** use `POST` with action paths (e.g. `POST /documents/document-delete`), not HTTP `DELETE`.

---

All endpoints: [llms.txt](https://api.paperoffice.ai/latest/docs/llms.txt) · Everything in one file: [llms-full.txt](https://api.paperoffice.ai/latest/docs/llms-full.txt) · [OpenAPI 3.1](https://api.paperoffice.ai/latest/docs/openapi.json) · This page: https://api.paperoffice.ai/latest/docs/endpoints/po-anonymization-anonymize-document.md

*Generated 2026-10-20 from live API documentation (release `R20261020.1635`).*
