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

# PII Filter

> Redact, block, or observe personal data in LLM responses at the proxy, with detections recorded as evidence

A `pii_filter` policy enforces on LLM responses routed through the MeshAI proxy. The highest-priority matching policy applies one of three actions before the response reaches the caller, and every detection is recorded as evidence in the Eval Log carrying type names and match counts only, never the matched values.

| Action    | Behavior                                                                               |
| --------- | -------------------------------------------------------------------------------------- |
| `redact`  | Matched PII is replaced with `[<TYPE>_REDACTED]` markers in the response body          |
| `block`   | The response is withheld; the caller receives a 403 `pii_detected` with the type names |
| `observe` | The response passes through unchanged; the detection is recorded as evidence           |

## Create a PII Filter Policy

```bash theme={null}
curl -X POST https://api.meshai.dev/api/v1/policies \
  -H "Authorization: Bearer msh_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "redact-pii-in-responses",
    "policy_type": "pii_filter",
    "rules": {
      "action": "redact",
      "pii_types": ["email", "ssn", "credit_card"],
      "fail_closed": false
    },
    "conditions": { "environments": ["production"] }
  }'
```

Rules are validated at creation, so a typo in `action` or an unknown type name is a 422, not a silent behavior change:

| Rule          | Values                                                                                                                       | Default   |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------- |
| `action`      | `redact`, `block`, `observe`                                                                                                 | `redact`  |
| `pii_types`   | List of type names from the table below                                                                                      | All types |
| `fail_closed` | `true` withholds the response (502) if the PII scan itself fails; `false` passes it through with a `scan_error` evidence row | `false`   |

Policies scope like any other: `conditions` supports `agent_ids`, `team_ids`, `environments`, and `risk_levels`. A one-click starter is available as the **PII redaction for customer-facing agents** [policy template](/governance/policies).

## Pattern Set

| PII Type        | Pattern                                                                             | Redacted As                |
| --------------- | ----------------------------------------------------------------------------------- | -------------------------- |
| `email`         | Email addresses                                                                     | `[EMAIL_REDACTED]`         |
| `phone_us`      | US-style phone numbers                                                              | `[PHONE_US_REDACTED]`      |
| `phone_intl`    | International phone numbers (leading `+`)                                           | `[PHONE_INTL_REDACTED]`    |
| `ssn`           | US Social Security Numbers                                                          | `[SSN_REDACTED]`           |
| `credit_card`   | 13 to 19 digit card numbers, **Luhn-validated** so order ids do not match           | `[CREDIT_CARD_REDACTED]`   |
| `ip_address`    | IPv4 and IPv6 (exhaustive form matching; MAC addresses and timestamps do not match) | `[IP_ADDRESS_REDACTED]`    |
| `passport`      | Passport numbers (common formats)                                                   | `[PASSPORT_REDACTED]`      |
| `iban`          | International Bank Account Numbers                                                  | `[IBAN_REDACTED]`          |
| `date_of_birth` | Dates anchored to DOB context ("DOB:", "born on", "date of birth")                  | `[DATE_OF_BIRTH_REDACTED]` |

Redaction scans each response text block independently and covers OpenAI (`choices[].message.content`) and Anthropic (`content[]` text blocks) response shapes. Non-JSON bodies pass through untouched.

## Evidence

Every detection writes a row to the Eval Log (`policy_evaluations`) with the policy id, the action taken, the PII type names, and per-type match counts. The matched values themselves never leave the scan. Blocked responses and scan failures are also visible in request telemetry as `error_type` values `pii_blocked` and `pii_scan_failed`.

Evidence rows ride the proxy's asynchronous telemetry pipeline: enforcement is synchronous and guaranteed, the evidence write is best-effort under extreme load.

## Scope and Limitations

* **Enforcement applies to proxy-routed traffic.** Agents observed only through passive OpenTelemetry ingest have no response bodies to scan; on that path a `pii_filter` policy records a `pass` evidence row ("deferred to proxy response path") so the policy stays visible in the Eval Log.
* **Streaming responses pass through unscanned.** SSE chunks can split a match across boundaries, so the filter applies to buffered (non-streaming) responses and does not pretend otherwise.
* Cost and token attribution always read the original upstream response, so redaction never distorts spend numbers.
