> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cloudraker.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cloudraker.com/_mcp/server.

# Redact

`POST /v1/redact` takes a file and returns a **new** file with the personal information gone. In a PDF the text is stripped out of the content stream, not covered with a rectangle — copy-paste and text search find nothing, because nothing is there. In audio the words are beeped or silenced and the transcript is rewritten.

## How it works

1. You send a **file** (a URL or a file id you already have) and, optionally, the `categories` that count as sensitive.
2. CloudRaker parses the document, locates every match, and rewrites the file destructively.
3. Routing is by the input's MIME type: audio and video go to audio redaction (`style`), everything else to document redaction (`mode`). Sending the other medium's parameter is a `400`.
4. The call **holds until the run finishes** — up to `?wait=` seconds (60 by default, 120 max), then degrades to `202` with a run id instead of erroring.
5. The run, its input, and the redacted output expire on their own (`ttl`, 24 hours by default) unless you [keep](/developers/runs#keep-a-run) them.

Redaction is destructive by design and the output is a new file — the original is left untouched. If you need the original gone, `DELETE /v1/files/:id` it, or let the run's `ttl` purge both.

## Quickstart

The sample uses a blank IRS Form W-9, so the call works with no local files.

```bash title="curl"
curl -X POST https://api.cloudraker.com/v1/redact \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": { "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf", "name": "w9.pdf" },
    "categories": ["ssn", "ein"],
    "mode": "targeted"
  }'
```

```ts title="TypeScript"
const res = await fetch("https://api.cloudraker.com/v1/redact", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CLOUDRAKER_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    file: { url: "https://www.irs.gov/pub/irs-pdf/fw9.pdf", name: "w9.pdf" },
    categories: ["ssn", "ein"],
    mode: "targeted",
  }),
});

const run = await res.json();
console.log(run.status, run.output?.entities);
```

```python title="Python"
import os, requests

res = requests.post(
    "https://api.cloudraker.com/v1/redact",
    headers={"Authorization": f"Bearer {os.environ['CLOUDRAKER_API_KEY']}"},
    json={
        "file": {"url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf", "name": "w9.pdf"},
        "categories": ["ssn", "ein"],
        "mode": "targeted",
    },
)

run = res.json()
print(run["status"], run.get("output", {}).get("entities"))
```

The TypeScript and Python samples are plain HTTP so they run with nothing installed. This endpoint is also a top-level method on both [SDKs](/developers/sdks) as of 0.3.0 — `client.redact(…)`; that page has a full worked example.

## Example response

```json
{
  "object": "redact_run",
  "id": "rdr_01KYD72106R2BXBJRF537T1JSH",
  "status": "processed",
  "expiresAt": "2026-07-26T18:02:06.093Z",
  "statusUrl": "/v1/runs/rdr_01KYD72106R2BXBJRF537T1JSH",
  "files": [
    { "id": "a04d6597-4e34-4a99-94ea-964c289a4c68", "name": "w9.pdf", "status": "processed" }
  ],
  "file": { "id": "a04d6597-4e34-4a99-94ea-964c289a4c68", "name": "w9.pdf", "status": "processed" },
  "output": {
    "file": {
      "id": "c8c8437a-0dfd-4924-9358-c638fb0002e4",
      "name": "w9 (redacted).pdf",
      "url": "https://cdn.cloudraker.com/…/latest?token=…"
    },
    "files": [
      { "id": "c8c8437a-0dfd-4924-9358-c638fb0002e4", "name": "w9 (redacted).pdf", "url": "https://cdn.cloudraker.com/…/latest?token=…" }
    ],
    "entities": { "ein": 5, "ssn": 10 },
    "skipped": 0
  }
}
```

## Key fields

| Field             | What it is                                                                                                 |
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
| `object`          | Always `redact_run`.                                                                                       |
| `id`              | The run id (`rdr_…`).                                                                                      |
| `status`          | `queued`, `processing`, `processed`, `failed`, `cancelled`, or `expired`.                                  |
| `files[]`         | The inputs, with per-file `status` and `error`. `file` is an alias for `files[0]`.                         |
| `output.files[]`  | One redacted file per input — `{id, name, url}`. `output.file` is an alias for the first.                  |
| `output.file.url` | Signed, time-limited download URL. `GET /v1/runs/:id/output/:name` is the stable alias for the same bytes. |
| `output.entities` | Count of redacted items per category, e.g. `{"ssn": 10, "ein": 5}`.                                        |
| `output.skipped`  | Detections that were found but could not be removed. Non-zero means review the output.                     |

The output file's bytes are registered a moment after the run reports `processed`. In that window `output.file` can arrive without its `url` and the `/output/` alias can answer `404` — re-fetch `GET /v1/runs/:id` and the URL will be there.

## Configuration

Every field is optional except `file`.

| Field          | Type                                  | What it does                                                                                                |
| -------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `file`         | `{url, name?, processing?}` or `{id}` | **Required.** The document or recording to redact.                                                          |
| `categories`   | array of strings, 1–50                | What counts as sensitive. Defaults cover names, government ids, addresses, phone, email, and date of birth. |
| `instructions` | string, ≤ 4000 chars                  | Free-text additions ("also redact internal project codenames").                                             |
| `mode`         | `targeted` \| `lines`                 | **Documents only.** `targeted` removes the matched span; `lines` removes the whole line containing it.      |
| `style`        | `beep` \| `silence`                   | **Audio only.** How the removed speech sounds in the output.                                                |
| `action`       | string                                | A [saved action](/capabilities/actions) — its id or slug. Inline fields are merged over its saved config.   |
| `metadata`     | object                                | Your own key/values, echoed back on the run body (not on webhook deliveries). Max 10 KB.                    |
| `webhook`      | `{url}` or `{id}`                     | Where to deliver terminal events. See [Webhooks](/developers/webhooks).                                     |
| `ttl`          | integer seconds, 1–604800             | How long the run and its files live. Default 24 hours, max 7 days.                                          |

Sending `style` on a PDF (or `mode` on audio) returns `400 invalid_request` naming the parameter that doesn't apply.

## Sync vs async

Identical to [extract](/capabilities/extract#sync-vs-async): synchronous by default, `?wait=` between `0` and `120` seconds, and a `202` handle instead of a timeout error at the cap.

```json
{
  "object": "redact_run",
  "id": "rdr_01KYD72106R2BXBJRF537T1JSH",
  "status": "processing",
  "statusUrl": "/v1/runs/rdr_01KYD72106R2BXBJRF537T1JSH"
}
```

Long recordings and large scans normally land here — pass `?wait=0` and poll, or use a webhook.

## Save as an action

Redaction policy is usually organization-wide, not per call. Save the `categories`, `instructions`, and `mode` once and every call shrinks to `{"file": …, "action": "hr-offboarding"}`:

```bash
curl -X POST https://api.cloudraker.com/v1/actions \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "capability": "redact",
    "name": "HR offboarding",
    "mimeType": "application/pdf",
    "config": { "categories": ["ssn", "email", "phone"], "mode": "lines" }
  }'
```

`mimeType` picks the variant (document or audio) at save time. See [Saved actions](/capabilities/actions).

## Next steps

#### [Saved actions](/capabilities/actions)

Save a redaction policy once and reference it by slug.

#### [Pipelines](/capabilities/pipeline)

Extract and redact the same file set in one call.

#### [Runs](/developers/runs)

Statuses, downloading outputs, TTL, and keeping a result.

#### [Errors](/developers/errors)

The error envelope and which failures are worth retrying.