> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slate.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# Automatically Redact Sensitive Data in PDF Documents

> Learn how to submit a PDF redaction job with custom rules, poll the lightweight status endpoint, and download the redacted output file from Slate.

Slate's redaction engine automatically locates and masks sensitive information — Social Security Numbers, account numbers, and custom patterns — in PDF documents before they are filed with courts or shared with external parties. Submit a redaction job, poll a lightweight status endpoint until processing finishes, then download the clean PDF via a presigned URL.

<Note>
  Slate applies **default redaction rules** to every job automatically. These include common SSN formats (e.g. `123-45-6789`, `123456789`) and account number variants derived from the matter's account data. Any custom `rules` you supply in the request body are merged with — not a replacement for — the default ruleset.
</Note>

<Steps>
  <Step title="Submit a redaction job">
    Call `POST /v1/redactions` to start a new redaction job. Slate queues the document for processing and immediately returns a job ID and a poll URL.

    **Required fields:**

    | Field      | Type | Description                    |
    | ---------- | ---- | ------------------------------ |
    | `matterId` | UUID | The matter the file belongs to |
    | `fileId`   | UUID | The uploaded file to redact    |

    Supply an optional `rules` array to add custom redaction patterns on top of the defaults. Each rule specifies a `match` strategy and a `transform` action.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.slate.inc/files/v1/redactions \
        -H 'Authorization: Bearer <token>' \
        -H 'Content-Type: application/json' \
        -d '{
          "matterId": "a1b2c3d4-0000-1111-2222-333344445555",
          "fileId": "b2c3d4e5-0000-1111-2222-333344445555",
          "rules": [
            {
              "match": { "type": "literal", "value": "123-45-6789" },
              "transform": { "type": "mask" }
            }
          ]
        }'
      ```

      ```json Example Request Body theme={null}
      {
        "matterId": "a1b2c3d4-0000-1111-2222-333344445555",
        "fileId": "b2c3d4e5-0000-1111-2222-333344445555",
        "rules": [
          {
            "match": { "type": "literal", "value": "123-45-6789" },
            "transform": { "type": "mask" }
          }
        ]
      }
      ```
    </CodeGroup>

    Slate responds with `202 Accepted` and a job object:

    ```json 202 Response theme={null}
    {
      "id": "7f3e2d1c-4b5a-6789-abcd-ef0123456789",
      "status": "pending",
      "pollUrl": "/v1/redactions/7f3e2d1c-4b5a-6789-abcd-ef0123456789"
    }
    ```

    Store the `id` (referred to as `redactionId` below). The `pollUrl` is the path to the job detail endpoint (`GET /v1/redactions/{redactionId}`); for lightweight polling use the dedicated status endpoint shown in the next step.

    <Tip>
      For scanned documents or image-based PDFs where text is not natively selectable, enable OCR by including `"configuration": { "ocr": { "enabled": true } }` in your request body. OCR processing takes longer but is required for Slate to detect sensitive data embedded in images.
    </Tip>
  </Step>

  <Step title="Poll for redaction status">
    Call `GET /v1/redactions/{redactionId}/status` to check processing progress. This endpoint is lightweight — it reads from Slate's job store, not from S3 — making it safe to poll frequently without incurring storage egress costs.

    ```bash cURL theme={null}
    curl -X GET https://api.slate.inc/files/v1/redactions/7f3e2d1c-4b5a-6789-abcd-ef0123456789/status \
      -H 'Authorization: Bearer <token>'
    ```

    ```json In-Progress Response theme={null}
    {
      "id": "7f3e2d1c-4b5a-6789-abcd-ef0123456789",
      "status": "processing",
      "completedOn": null,
      "redactionDuration": null,
      "errorMessage": null,
      "summary": null
    }
    ```

    ```json Completed Response theme={null}
    {
      "id": "7f3e2d1c-4b5a-6789-abcd-ef0123456789",
      "status": "completed",
      "completedOn": "2024-05-01T12:00:47Z",
      "redactionDuration": "47.2s",
      "errorMessage": null,
      "summary": {
        "ocrUsed": true,
        "rules": [
          {
            "textCount": 3,
            "ocrCount": 0,
            "redactions": []
          },
          {
            "textCount": 0,
            "ocrCount": 2,
            "redactions": [
              { "page": 1, "x": 72.5, "y": 144.0, "w": 68.2, "h": 12.0, "confidence": 96.4, "source": "ocr" },
              { "page": 2, "x": 90.0, "y": 200.5, "w": 68.2, "h": 12.0, "confidence": 91.8, "source": "ocr" }
            ]
          }
        ]
      }
    }
    ```

    Poll until `status` is `"completed"` or `"failed"`. Possible status values:

    | Status       | Meaning                                                 |
    | ------------ | ------------------------------------------------------- |
    | `pending`    | Job accepted; waiting for a processing slot             |
    | `processing` | Engine is actively scanning the PDF                     |
    | `completed`  | Redaction finished; redacted file is ready to download  |
    | `failed`     | Processing error — check `errorMessage` in the response |

    Use exponential backoff starting at 3 seconds. Most documents complete within 15–60 seconds depending on page count and whether OCR is enabled.
  </Step>

  <Step title="Download the redacted PDF">
    Once `status` is `"completed"`, retrieve the redacted file by calling `GET /v1/redactions/{redactionId}/file`. Slate returns a presigned S3 URL pointing to the output document. Calling this before the job reaches `completed` returns `409`.

    ```bash Inline Viewing theme={null}
    curl -X GET https://api.slate.inc/files/v1/redactions/7f3e2d1c-4b5a-6789-abcd-ef0123456789/file \
      -H 'Authorization: Bearer <token>'
    ```

    ```bash Force Download theme={null}
    curl -X GET 'https://api.slate.inc/files/v1/redactions/7f3e2d1c-4b5a-6789-abcd-ef0123456789/file?download=true' \
      -H 'Authorization: Bearer <token>'
    ```

    ```json Example Response theme={null}
    {
      "url": "https://slate-outputs.s3.amazonaws.com/redacted/7f3e2d1c-4b5a-6789-abcd-ef0123456789.pdf?X-Amz-Expires=900&..."
    }
    ```

    * **Omit `?download=true`** to get a URL suitable for inline browser rendering (PDF viewer, iframe).
    * **Add `?download=true`** to get a URL with `Content-Disposition: attachment`, which forces the browser to prompt a file download.

    <Note>
      The presigned download URL expires after **15 minutes**. If your downstream consumer needs persistent access, store the `redactionId` and call this endpoint again to generate a fresh URL rather than caching the presigned URL itself.
    </Note>
  </Step>

  <Step title="Review the run summary">
    The completed status response includes a full run summary you can use for auditing, quality review, or reporting. Key fields:

    | Field                          | Type    | Description                                                                                                                                             |
    | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `redactionDuration`            | string  | Total processing time as a Go duration string (e.g. `350ms`, `47.2s`, `1h30s`)                                                                          |
    | `summary.ocrUsed`              | boolean | Whether OCR was run during this job                                                                                                                     |
    | `summary.rules[].textCount`    | number  | Matches found via native PDF text extraction                                                                                                            |
    | `summary.rules[].ocrCount`     | number  | Additional matches found via OCR (0 if OCR disabled)                                                                                                    |
    | `summary.rules[].redactions[]` | array   | Bounding boxes for OCR-located redactions (`page`, `x`, `y`, `w`, `h`, `confidence`, `source`). Empty for text-only rules, whose matches are count-only |

    A non-zero `ocrCount` on a rule confirms that OCR detected sensitive data that was not accessible from the raw PDF text layer — useful evidence that OCR should remain enabled for that document type going forward.

    <Note>
      Slate supports a **labeling option** that annotates each redaction box with a configurable label style rather than a plain black mask. Enable labeling by including `"labeling": { "mode": "numbers", "ranges": [{ "startPage": 1, "endPage": 5 }] }` in your job submission payload. Accepted modes are `numbers`, `letters`, `pageNumbers`, and `none`.
    </Note>
  </Step>
</Steps>
