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

# Guardrails and PII redaction for the Responses API

> Redact PII from prompts and responses by configuring key-level guardrails or calling the redact-v1 model directly on /v1/responses.

## Overview

Guardrails let you redact sensitive data automatically when using an API key.

* Configure guardrails once on an API key.
* Use that key normally with `/v1/responses`.
* Redaction applies automatically based on that key's settings.

You can also call the `redact-v1` model directly to get a scrubbed copy of your input without invoking an LLM. See [Redact as a model](#redact-as-a-model).

<Info>
  Guardrails are key-level settings, not request-body parameters on `/v1/responses`.
</Info>

## Configure in Dashboard

1. Go to **Guardrails**
2. Select an API key
3. Enable redaction
4. Choose target: `input`, `output`, or `both`
5. Select entity types
6. Save changes

## Settings in UI

* **Enabled / Disabled**: turns redaction on or off for the selected key.
* **Target**: choose whether redaction applies to input, output, or both.
* **Entity Types**: choose which categories of sensitive data to redact.

## Behavior You Can Expect

* `target: "input"` redacts sensitive content before model processing.
* `target: "output"` redacts model output before the response is returned.
* `target: "both"` applies both.

<Warning>
  Output redaction is not applied to streamed responses (`"stream": true`). Use non-streamed requests if you need output redaction.
</Warning>

## What gets redacted

Input redaction scrubs text in these `input` items:

* Message text, for every role
* Plaintext `agent_message` content
* Function call arguments and outputs
* Custom tool call inputs and outputs
* Reasoning summaries and reasoning text
* Web search actions (queries and URLs)

Output redaction scrubs assistant message text and reasoning text.

These are not redacted:

* Images and files
* The request's `tools` and `instructions`
* Streamed output (see the warning above). Clients that always stream, such as Codex, get input redaction only.

## Tips

* Start with `target: "input"` if your main goal is protecting prompt data.
* Use `target: "both"` for stricter protection on non-streamed calls.
* Use `entity_types` to avoid over-redacting low-risk data.

## Entity types

These are the entity types you can select when configuring redaction, grouped by category. Selecting a type redacts every detected occurrence of it, replacing the match with a placeholder token such as `[EMAIL]` (or the custom placeholder configured on your key).

### Personally Identifiable Information (PII)

Information that can identify an individual.

| Entity type | Redacts |
| - | - |
| `PERSON` | People's names |
| `EMAIL` | Email addresses |
| `PHONE` | Phone numbers |
| `SSN` | Social Security numbers |
| `DATE_OF_BIRTH` | Dates of birth |
| `AGE` | Ages |
| `DRIVERS_LICENSE` | Driver's license numbers |
| `PASSPORT` | Passport numbers |
| `LOCATION` | Physical locations and addresses |
| `USERNAME` | Usernames and handles |

### Payment Card Industry (PCI)

Financial and payment card data.

| Entity type | Redacts |
| - | - |
| `CREDIT_CARD` | Credit card numbers |
| `CREDIT_CARD_CVV` | Card CVV codes |
| `ACCOUNT_NUMBER` | Bank account numbers |
| `IBAN` | IBANs |
| `AMOUNT` | Monetary amounts |
| `CRYPTO_ADDRESS` | Cryptocurrency wallet addresses |

### Protected Health Information (PHI)

HIPAA-protected health information.

| Entity type | Redacts |
| - | - |
| `PATIENT` | Patient names |
| `STAFF` | Medical staff names |
| `HOSPITAL` | Hospital and facility names |
| `PATIENT_ID` | Patient identifiers |
| `MEDICAL_RECORD_NUMBER` | Medical record numbers |
| `NPI` | National Provider Identifiers |
| `MEDICAL_CONDITION` | Medical conditions and diagnoses |
| `MEDICATION` | Medication names |
| `OTHER_PHI` | Other protected health information |

### Credentials & Secrets

Authentication credentials and API keys.

| Entity type | Redacts |
| - | - |
| `PASSWORD` | Passwords |
| `JWT_TOKEN` | JWTs |
| `AWS_ACCESS_KEY` | AWS access key IDs |
| `AWS_SECRET_KEY` | AWS secret access keys |
| `OPENAI_API_KEY` | OpenAI API keys |
| `ANTHROPIC_API_KEY` | Anthropic API keys |
| `GOOGLE_API_KEY` | Google API keys |
| `AZURE_API_KEY` | Azure API keys |
| `GCP_SERVICE_ACCOUNT` | GCP service account credentials |

### Technical Identifiers

Network and technical identifiers.

| Entity type | Redacts |
| - | - |
| `IP_ADDRESS` | IP addresses |
| `MAC_ADDRESS` | MAC addresses |
| `URL` | URLs |
| `UUID` | UUIDs |
| `VIN` | Vehicle identification numbers |

### Organizations

| Entity type | Redacts |
| - | - |
| `ORGANIZATION` | Business and organization names |

### Temporal Data

| Entity type | Redacts |
| - | - |
| `DATE` | Dates |

## Redact as a model

Set `model` to `redact-v1` (aliases: `redact`, `concentrate-redact`) on `/v1/responses` to redact your input without forwarding it to an upstream LLM. The response returns the scrubbed payload directly, which is useful for:

* Pre-processing prompts before sending them to a different model or system.
* Building redaction into pipelines that don't issue downstream LLM calls.
* Auditing what guardrails would strip from a given input.

### Requirements

* The API key used for the request must have redaction guardrails enabled with at least one entity type selected. Requests fail with `400` otherwise.
* The model uses the entity types, placeholder, and confidence threshold from the key's guardrail settings. The `target` setting is ignored, since `redact-v1` always returns redacted input.

### Step-by-step walkthrough

#### Step 1: Enable guardrails on your API key

In the dashboard, go to **Guardrails**, select the API key you'll use, enable redaction, and select at least one entity type — say `PERSON`, `EMAIL`, `PHONE`, and `CREDIT_CARD`. The `target` setting doesn't matter for `redact-v1`; it's ignored.

Without this step, any `redact-v1` request with that key returns a `400`.

#### Step 2: Send a request

Call `/v1/responses` exactly as you would for any other model, with `model` set to `redact-v1`:

```bash theme={null}
curl https://api.concentrate.ai/v1/responses \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "redact-v1",
    "input": "Hi, this is Jane Doe. Email me at jane@example.com or call 555-867-5309. My card is 4111 1111 1111 1111."
  }'
```

#### Step 3: Read the response

The reply follows the standard Responses shape. The redacted text appears in `output[0].content[0].text`, and a full `redact` summary is attached to the reply with the lossless scrubbed payload and any entities that were stripped. A response to the request above looks like this (values are illustrative):

```json theme={null}
{
  "id": "resp_6f2c1a8e4b0d4c59",
  "object": "response",
  "created_at": 1780683143,
  "completed_at": 1780683143,
  "status": "completed",
  "model": "concentrate/redact-v1",
  "output": [
    {
      "type": "message",
      "id": "msg_9d41e7c2a3f8",
      "status": "completed",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "Hi, this is [PERSON]. Email me at [EMAIL] or call [PHONE]. My card is [CREDIT_CARD].",
          "annotations": []
        }
      ]
    }
  ],
  "error": null,
  "tools": [],
  "usage": {
    "input_tokens": 33,
    "input_tokens_details": { "cached_tokens": 0 },
    "output_tokens": 0,
    "output_tokens_details": { "reasoning_tokens": 0 },
    "total_tokens": 33
  },
  "cost": {
    "total": 0.00000825,
    "byok": false,
    "breakdown": {
      "concentrate/redact-v1": {
        "input_tokens": 33,
        "input_tokens_details": { "cached_tokens": 0 },
        "output_tokens": 0,
        "output_tokens_details": { "reasoning_tokens": 0 },
        "total_tokens": 33
      }
    }
  },
  "redact": {
    "entities_found": 4,
    "entity_types": ["PERSON", "EMAIL", "PHONE", "CREDIT_CARD"],
    "models_used": ["regex", "gliner_base", "pii_deberta", "piiranha_credit"],
    "execution_time_ms": 141,
    "redaction_coverage": 0.8769,
    "redacted_input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Hi, this is [PERSON]. Email me at [EMAIL] or call [PHONE]. My card is [CREDIT_CARD]."
          }
        ]
      }
    ],
    "redacted_tools": []
  }
}
```

What each part means:

* `output` — the redacted input, remapped into assistant `output_text` messages so any Responses-compatible client can read it in the usual place. Only `message` and `function_call` items appear here.
* `redact.redacted_input` — the lossless scrubbed copy of your entire `input` array, in its original shape (including items like `function_call_output` that have no output representation).
* `redact.redacted_tools` — a scrubbed copy of the request's `tools`, if any were sent.
* `redact.entities_found` — total number of entities that were redacted.
* `redact.entity_types` — the entity types actually detected in this request (not the full set configured on the key).
* `redact.models_used`, `redact.execution_time_ms`, `redact.redaction_coverage` — detection diagnostics.

#### Step 4: Handle the failure case

If the key doesn't have redaction guardrails enabled with at least one entity type, the request is rejected before routing:

```json theme={null}
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Redaction guardrails must be enabled (with at least one entity type) on this key to use this model."
}
```

Fix it by completing Step 1 for that key.

### Structured input example

`redact-v1` accepts the full Responses `input` array, and redacts text everywhere it can appear — message content, function call arguments, function call outputs, and tool definitions:

```bash theme={null}
curl https://api.concentrate.ai/v1/responses \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "redact-v1",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [{ "type": "input_text", "text": "contact jane@example.com" }]
      },
      {
        "type": "function_call",
        "call_id": "call_1",
        "name": "send_email",
        "arguments": "{\"email\":\"jane@example.com\"}"
      },
      {
        "type": "function_call_output",
        "call_id": "call_1",
        "output": "sent to jane@example.com"
      }
    ]
  }'
```

In the reply, the `message` and `function_call` items come back redacted in `output`; the `function_call_output` item has no output-item representation, so it appears only in `redact.redacted_input`:

```json theme={null}
{
  "output": [
    {
      "type": "message",
      "id": "msg_1c8f2b6d90aa",
      "status": "completed",
      "role": "assistant",
      "content": [
        { "type": "output_text", "text": "contact [EMAIL]", "annotations": [] }
      ]
    },
    {
      "type": "function_call",
      "id": "fc_7b3e9a4c51d2",
      "call_id": "call_1",
      "name": "send_email",
      "arguments": "{\"email\":\"[EMAIL]\"}"
    }
  ],
  "redact": {
    "entities_found": 3,
    "entity_types": ["EMAIL"],
    "redacted_input": [
      {
        "type": "message",
        "role": "user",
        "content": [{ "type": "input_text", "text": "contact [EMAIL]" }]
      },
      {
        "type": "function_call",
        "call_id": "call_1",
        "name": "send_email",
        "arguments": "{\"email\":\"[EMAIL]\"}"
      },
      {
        "type": "function_call_output",
        "call_id": "call_1",
        "output": "sent to [EMAIL]"
      }
    ],
    "redacted_tools": []
  }
}
```

### Streaming

`"stream": true` is supported with `redact-v1`: the gateway synthesizes the standard Responses SSE event lifecycle from the redaction result, so streaming clients work unchanged.

## Related Documentation

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/docs/getting-started/quickstart">
    Get started with API keys and first requests
  </Card>

  <Card title="Streaming" icon="water" href="/docs/api-reference/endpoint/streaming">
    Streaming behavior and event format
  </Card>
</CardGroup>
