# Redact API reference

> Pseudonymise text, find personal data and put the originals back. Send short texts synchronously and long documents as encrypted text jobs; PDF and Word files are in beta. Organisation integration keys and personal keys both work here.

Request and response schemas, with examples, are in the OpenAPI document: https://developers.komplai.dk/openapi.json

## POST /v1/redact

**Pseudonymise a text**

Replaces personal data with labels such as [PERSON-1] and returns the pseudonymised text in redacted. Choose the layers in detectors: regex (rules for CPR numbers, phone numbers, e-mail addresses and more), ner (a model for names, organisations and addresses) and llm (a language model for what rules and NER miss, such as health data in free text). Without detectors, regex and ner run. Rules run on komplai's servers in Germany (EU), and NER at the place in nerDeployment or, without one, at the default place GET /v1/access marks. The language model runs on komplai's local infrastructure in Denmark by default; processing eu-cloud uses komplai's EU cloud, needs llm in detectors and EU processing approved for your organisation, and counts towards the organisation's monthly AI spending cap. Your organisation's own redaction rules always apply.

Use this call for short texts such as a letter or a note: at most 750,000 UTF-16 code units, and work that finishes within 300 seconds. Before anything runs, the call estimates the time from komplai's measured speeds with an empty queue; a run whose estimate exceeds the hold is refused with 413 use_job, its estimatedSeconds and holdSeconds, and nothing is processed or charged. The estimate cannot cover an EU language model, which has no measured speed yet, time spent waiting in the shared queue, or a text that takes longer than a typical one: such a run can still reach the hold and end with 504 processing_timeout and no result, and calls already sent to the EU cloud count towards the monthly AI spending cap. Send long texts and EU runs as a text job (POST /v1/redact/jobs), or send this call with the header Prefer: respond-async to get 202 and a job instead. Without that header the call never turns into a job. PDF and Word files go to POST /v1/redact/file. Ask for include reports only when you need them: they contain the originals. A failed call returns no partial result. engine agentic (preview) requires the organisation administrator's opt-in (403 when absent) and processing local; it reads up to 2,000,000 UTF-16 code units as a job, while a synchronous call takes what it can finish in time. External lookups require explicit per-run sources and the administrator's current source permission. No method guarantees anonymity; check the result.

Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.

- Operation id: `redactText`
- Scopes: `redact:process`
- Parameters: `prefer` (header), `idempotency-key` (header)
- Responses: 200, 202, 400, 401, 403, 409, 413, 415, 429, 502, 503, 504

## POST /v1/redact/detect

**Find personal data in a text**

Returns what regex and NER find, with UTF-16 offsets into your text, without changing it. At most 16,000 UTF-16 code units and 100,000 bytes per call; split longer texts or use POST /v1/redact. Rules run on komplai's servers in Germany (EU), and NER at the place you choose with nerDeployment or, without one, at the default place GET /v1/access marks (it lists the places). No language model runs here. Your organisation's own redaction rules apply, as on POST /v1/redact: a rule's match is returned with type and source custom and the rule's label in customLabel, and a finding that an allow rule covers is left out.

- Operation id: `detectPersonalData`
- Scopes: `redact:detect`
- Responses: 200, 400, 401, 403, 413, 415, 429, 502, 503

## POST /v1/redact/restore

**Restore the originals in a text**

Puts the originals back into text with labels such as [PERSON-1], for example an answer from your own model or workflow step. Send either the mapping from POST /v1/redact (asked for with include ["mapping"]) or the id of your own finished text job; with a job, komplai reads its retained result and you do not hold the mapping. Labels match regardless of case and spaces inside the brackets. Labels the mapping does not contain stay unchanged and are listed in unknownPlaceholders. Fixed replacement tokens from your organisation's redaction rules can stand for several originals, so they are never restored; those in the text are listed in fixedTokens. No model runs and the call has no AI charge; it counts against your request rate. The response contains originals: protect it as personal information.

- Operation id: `restoreRedactText`
- Scopes: `redact:process`
- Responses: 200, 400, 401, 403, 404, 409, 410, 413, 415, 429, 503

## POST /v1/redact/jobs

**Submit a text job**

Stores the text encrypted and pseudonymises it in the background with the same options as POST /v1/redact, up to 2,000,000 UTF-16 code units (about 800 standard pages of 2,400 characters). Use it for long documents, also below the 300-second limit of a synchronous call. The answer is 202 with the job's id, and Location points to its status. Poll GET /v1/redact/jobs/{id}, at most every few seconds because reads count against the request limit, then read GET /v1/redact/jobs/{id}/result. Ask for include mapping or changes if you want to restore from the job with POST /v1/redact/restore. Personal data needs an approved storage policy for text jobs; the result stays encrypted until you delete the job or it expires, and the retention period counts from when the job ends. A job has no time limit of its own while it makes progress: it waits for the shared queue, every model call has a budget from the model's measured speed, and a job that makes no progress for 65 minutes fails with redact_job_stalled. A job belongs to the key that created it. A NER place or local language model the job names is checked against the settings when it is submitted, and whether it answers when the job runs; one that does not answer then fails the job with its code. A job that is interrupted (a restart or a lost worker) resumes from its encrypted checkpoint and sends at most the step that was in flight again: a call to the language model on local infrastructure gets its answer back from the queue when the queue finished it, and runs once more when the interruption cut it off, a call to the EU cloud is sent again once and counted towards the monthly AI spending cap like any call, and a register lookup is sent again; each is logged. After three interruptions the job ends with redact_job_attempts_exhausted. engine agentic (preview) requires the organisation administrator's opt-in (403 when absent) and processing local, and reads up to the same 2,000,000 UTF-16 code units in windows; external sources require explicit per-run selection and current administrator permission.

Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.

- Operation id: `submitRedactJob`
- Scopes: `redact:process`
- Parameters: `idempotency-key` (header)
- Responses: 202, 400, 401, 403, 409, 413, 415, 429, 503

## GET /v1/redact/jobs/{id}

**Read the status of a text job**

state is queued, running, succeeded, failed, cancelled or invalidated. Read the result once it is succeeded. A failed, cancelled or invalidated job is final and carries error with the reason. Wait at least 2 seconds between reads: each read counts against the request limit.

- Operation id: `getRedactJob`
- Scopes: `redact:process`
- Parameters: `id` (path, required)
- Responses: 200, 400, 401, 403, 404, 429, 503

## DELETE /v1/redact/jobs/{id}

**Delete a text job**

Cancels the job if it is still queued or running and deletes its encrypted text and result at once. Cancellation is final. Only the encrypted replay fingerprint for Idempotency-Key remains until the original expiry. Deleting a job that is already cancelled answers the same 200. Send no body. Deleting does not count against the request limit.

- Operation id: `deleteRedactJob`
- Scopes: `redact:process`
- Parameters: `id` (path, required)
- Responses: 200, 400, 401, 403, 404, 429, 503

## GET /v1/redact/jobs/{id}/result

**Read the result of a text job**

200 with the same result as POST /v1/redact once the job has succeeded. 202 with the job's status while it is queued or running; wait Retry-After seconds. 410 when it failed, was cancelled or was invalidated. Reading does not delete the encrypted result: DELETE removes text and result at once, and expiry removes the job and its replay fingerprint.

- Operation id: `getRedactJobResult`
- Scopes: `redact:process`
- Parameters: `id` (path, required)
- Responses: 200, 202, 400, 401, 403, 404, 410, 429, 503

## POST /v1/redact/file

**Pseudonymise the text of a PDF or Word file (beta)** (Beta)

Beta. Send a PDF with a text layer or a Word .docx as base64 in JSON; komplai extracts its text and runs the same Redact processing as for text, with the same options. The response is pseudonymised text, not a redacted file. No OCR runs: a scanned page is refused (422 scanned_pages_not_supported, with the page numbers) unless allowPagesWithoutText is true. The text is extracted on komplai's API servers (EU · Germany) in memory; the file is not stored. File problems: 400 unsupported_file_type, file_type_mismatch, invalid_file_encoding, empty_file; 413 file_too_large, too_many_pages, text_too_large, file_too_complex; 422 invalid_file, encrypted_file, no_text_found, scanned_pages_not_supported; 429 processing_capacity_busy while other files are being read. No method guarantees anonymity; check the result. At most 750,000 UTF-16 code units of extracted text, and work that finishes within 300 seconds: a run whose estimate exceeds that is refused with 413 use_job and its estimate before anything is processed, and one the estimate cannot cover (an EU language model, a wait in the shared queue) can still end with 504 processing_timeout, as on POST /v1/redact. Longer files go to POST /v1/redact/file/jobs, or send this call with Prefer: respond-async to get 202 and a job. pages gives each page's offsets in the extracted text and in redacted. Agentic processing has the same requirements as on POST /v1/redact.

Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.

- Operation id: `redactFile`
- Scopes: `redact:process`
- Parameters: `prefer` (header), `idempotency-key` (header)
- Responses: 200, 202, 400, 401, 403, 409, 413, 415, 422, 429, 502, 503, 504

## POST /v1/redact/file/jobs

**Submit a PDF or Word file as a text job (beta)** (Beta)

Beta. Send a PDF with a text layer or a Word .docx as base64 in JSON; komplai extracts its text and runs the same Redact processing as for text, with the same options. The response is pseudonymised text, not a redacted file. No OCR runs: a scanned page is refused (422 scanned_pages_not_supported, with the page numbers) unless allowPagesWithoutText is true. The text is extracted on komplai's API servers (EU · Germany) in memory; the file is not stored. File problems: 400 unsupported_file_type, file_type_mismatch, invalid_file_encoding, empty_file; 413 file_too_large, too_many_pages, text_too_large, file_too_complex; 422 invalid_file, encrypted_file, no_text_found, scanned_pages_not_supported; 429 processing_capacity_busy while other files are being read. No method guarantees anonymity; check the result. The text is extracted while you wait and submitted as a text job, exactly as POST /v1/redact/jobs, up to 2,000,000 UTF-16 code units. The 202 response adds the file's page offsets in the extracted text; poll and read the result, restore and delete with the /v1/redact/jobs/{id} operations.

Organisation integration keys cannot use engine agentic: 403 integration_not_permitted.

- Operation id: `submitRedactFileJob`
- Scopes: `redact:process`
- Parameters: `idempotency-key` (header)
- Responses: 202, 400, 401, 403, 409, 413, 415, 422, 429, 503

---

https://developers.komplai.dk/reference/redact
