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

# PII Redaction | AI Gateway

> Redact personally identifiable information before it reaches the provider, then restore the original values in the response, using the pii_redaction plugin in the AI Gateway.

**Use Cases**

* Keeping names, emails, and account numbers out of third-party provider logs.
* Meeting data-handling requirements without rewriting prompts in every service.
* Sending sensitive support tickets to a model while preserving the reply for the end user.
* Excluding raw PII from trace storage while still tracing the request end to end.

***

The `pii_redaction` plugin detects personally identifiable information in the request, replaces each value with a placeholder before the provider sees it, and restores the original values in the response. The provider receives only placeholders such as `<EMAIL_ADDRESS_1>` or `<PERSON_2>`.

## Quick Start

Add a `pii_redaction` entry to the `plugins` array.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-4o-mini",
      "input": "Email the invoice to jane.doe@example.com",
      "plugins": [{ "id": "pii_redaction", "language": "en" }]
    }'
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import OpenAI from 'openai';

  const client = new OpenAI({
    apiKey: process.env.ORQ_API_KEY,
    baseURL: 'https://api.orq.ai/v3/router',
  });

  const response = await client.responses.create({
    model: 'openai/gpt-4o-mini',
    input: 'Email the invoice to jane.doe@example.com',
    plugins: [{ id: 'pii_redaction', language: 'en' }],
  });

  console.log(response.output_text);
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from openai import OpenAI
  import os

  client = OpenAI(
      api_key=os.environ.get("ORQ_API_KEY"),
      base_url="https://api.orq.ai/v3/router",
  )

  response = client.responses.create(
      model="openai/gpt-4o-mini",
      input="Email the invoice to jane.doe@example.com",
      extra_body={
          "plugins": [{"id": "pii_redaction", "language": "en"}]
      },
  )

  print(response.output_text)
  ```

  ```typescript TypeScript (Chat Completions) theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import OpenAI from 'openai';

  const client = new OpenAI({
    apiKey: process.env.ORQ_API_KEY,
    baseURL: 'https://api.orq.ai/v3/router',
  });

  const response = await client.chat.completions.create({
    model: 'openai/gpt-4o-mini',
    messages: [
      { role: 'user', content: 'Email the invoice to jane.doe@example.com' },
    ],
    plugins: [{ id: 'pii_redaction', language: 'en' }],
  });
  ```
</CodeGroup>

## How it works

The plugin runs a redaction round-trip around the generation:

1. **Redact**: detected PII in the request is replaced with typed placeholders before the request leaves the **AI Gateway**.
2. **Generate**: the provider processes the placeholder text and returns a response that keeps the placeholders intact.
3. **Restore**: the original values are substituted back into the response before it returns to the caller.

On `embeddings`, `rerank`, and `images/generations`, the plugin redacts the input only. The `rerank` response restores the echoed document text; `embeddings` and image generation have no echoed text to restore.

## Configuration

| Parameter    | Type      | Required | Description                                                                                           |
| ------------ | --------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `id`         | string    | Yes      | Plugin discriminator. Must be `pii_redaction`.                                                        |
| `language`   | string    | No       | Detector language: `en` or `nl`. Defaults to `en`.                                                    |
| `entities`   | string\[] | No       | Restricts redaction to a subset of entity types. Omit to redact every type detected for the language. |
| `on_failure` | string    | No       | Behavior when redaction is unavailable: `block` or `passthrough`. Defaults to `block`.                |
| `threshold`  | number    | No       | Detector confidence cutoff in `[0,1]`. Defaults to the provider setting.                              |

### Restrict to specific entities

Pass `entities` to redact only the listed types. The list is case-insensitive and must match the selected language catalog.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v3/router/responses \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-4o-mini",
      "input": "Contact Jane Doe at jane.doe@example.com",
      "plugins": [{
        "id": "pii_redaction",
        "language": "en",
        "entities": ["EMAIL_ADDRESS"]
      }]
    }'
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const response = await client.responses.create({
    model: 'openai/gpt-4o-mini',
    input: 'Contact Jane Doe at jane.doe@example.com',
    plugins: [
      { id: 'pii_redaction', language: 'en', entities: ['EMAIL_ADDRESS'] },
    ],
  });
  ```
</CodeGroup>

## Failure modes

The `on_failure` policy decides what happens when the detection service cannot run:

| Mode          | Behavior                                                                         |
| ------------- | -------------------------------------------------------------------------------- |
| `block`       | Fails closed. The request is rejected and nothing reaches the provider. Default. |
| `passthrough` | Fails open. The original, un-redacted text is sent to the provider.              |

## Supported languages

The detectable entity catalog differs per language.

<AccordionGroup>
  <Accordion title="English (en)">
    `AGE`, `API_KEY`, `BANK_ROUTING`, `BIC`, `BIOMETRIC_ID`, `BLOOD_TYPE`,
    `BSN`, `CREDIT_CARD`, `CRYPTO`, `DATE_TIME`, `DEVICE_ID`, `EDUCATION_LEVEL`,
    `EMAIL`, `EMAIL_ADDRESS`, `EMPLOYMENT_STATUS`, `GENDER`, `HEALTH_PLAN_ID`,
    `HTTP_COOKIE`, `IBAN_CODE`, `ID`, `ID_CARD`, `IMEI`, `IP_ADDRESS`,
    `JOBTITLE`, `JWT`, `KVK_NUMBER`, `LANGUAGE`, `LICENSE_NUMBER`,
    `LICENSE_PLATE`, `LOCATION`, `MAC_ADDRESS`, `MEDICAL_LICENSE`,
    `MEDICAL_RECORD`, `NRP`, `ORGANIZATION`, `PASSPORT`, `PASSWORD`, `PERSON`,
    `PHONE_NUMBER`, `PIN`, `POLITICAL_VIEW`, `RACE_ETHNICITY`,
    `RELIGIOUS_BELIEF`, `SEXUALITY`, `TAX_ID`, `TITLE`, `UK_NHS`, `URL`,
    `US_BANK_NUMBER`, `US_DRIVER_LICENSE`, `US_ITIN`, `US_PASSPORT`, `US_SSN`,
    `UUID`, `VEHICLE_ID`
  </Accordion>

  <Accordion title="Dutch (nl)">
    `AGE`, `API_KEY`, `BANK_ROUTING`, `BIC`, `BIOMETRIC_ID`, `BLOOD_TYPE`,
    `BSN`, `CREDIT_CARD`, `CRYPTO`, `DATE_TIME`, `DEVICE_ID`, `EDUCATION_LEVEL`,
    `EMAIL`, `EMAIL_ADDRESS`, `EMPLOYMENT_STATUS`, `GENDER`, `HEALTH_PLAN_ID`,
    `HTTP_COOKIE`, `IBAN_CODE`, `ID`, `ID_CARD`, `IMEI`, `IP_ADDRESS`,
    `KVK_NUMBER`, `LANGUAGE`, `LICENSE_NUMBER`, `LICENSE_PLATE`, `LOCATION`,
    `MAC_ADDRESS`, `MEDICAL_RECORD`, `NRP`, `ORGANIZATION`, `PASSPORT`,
    `PASSWORD`, `PERSON`, `PHONE_NUMBER`, `PIN`, `POLITICAL_VIEW`,
    `RACE_ETHNICITY`, `RELIGIOUS_BELIEF`, `SEXUALITY`, `TAX_ID`, `TITLE`, `URL`,
    `US_DRIVER_LICENSE`, `US_SSN`, `VEHICLE_ID`
  </Accordion>
</AccordionGroup>

## Tracing

Redaction is traced in-process as child spans of the request: `pii-redact` for the input pass and `pii-restore` for the output pass. Each span carries the detector `language`, the failure policy, the requested entity count, the placeholder count, and the outcome.
