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

> ## Agent Instructions
> The OpenAPI document at /api-reference/openapi.yaml defines the target contract. Its x-reflections-availability field and each operation's availability notice identify supported test and live forms. Do not infer implementation from a schema or code sample. Live keys support account details, reads of the licenses the calling account holds as licensee or issued as talent (GET /v1/licenses?role=issuer), and GET /v1/generations?license=… for the state of outputs under such a license (summaries only: no prompt, reference, bytes or metadata). Live image checks, submissions and receipts are built but not activated: until activation, a live POST /v1/checks or /v1/generations returns 403 live_not_activated, which must not be retried. Discovery and JWKS are at the origin root (https://app.reflections.ai/.well-known/...), not under /v1.
> Three rules hold everywhere: a decision is never an error (deny and escalate are 200 responses, and a live check still evaluating is a 202 with status checking); generate nothing for a named talent without an allow; deliver nothing until the generation is allow.
> The sandbox accepts personal rk_test_ keys. Persist a separate Idempotency-Key and body for each logical /v1 POST; retry an unknown outcome with the same key and body. OAuth and Talent API MCP remain planned.

# Privacy modes

> Choose how much prompt text a check sends with full, redacted or withheld modes, and what each one costs.

<Note>
  Protocol reference. The current sandbox uses fictional fixtures and deterministic decisions,
  not production prompt evaluation. The retention and production processing contract below does
  not establish that those production services are available. Use only synthetic test data.
  Start with the [runnable quickstart](/quickstart) and [sandbox support matrix](/sandbox).
</Note>

A check works best when it sees the request your model receives. Some prompts carry personal data
about your users or other people, and some platforms cannot send prompt text at all. The check's
`prompt_handling` lets you choose how much text Reflections receives, and how long it keeps it.

## The three modes

| `prompt_handling.mode` | What Reflections receives | What the check can decide |
| - | - | - |
| `full` (default) | The text as your model receives it | Everything, including rules about what the prompt asks for |
| `redacted` | The text with personal data you removed | Everything that does not depend on the removed data |
| `withheld` | No text. Structured fields and digests only. | Who and how, from `talent`, `use` and media. Rules that need the text move to the generation. |

Reflections never claims to have read text it did not receive. Receipts state their `assurance`,
and in `withheld` mode the check's text-based rules are checked on the output instead.

## Full

Send the text as is. Resolution finds talent by name, alias or indirect reference, and the
license's rules are checked against what the request asks for before you spend anything on
generation. Use `full` unless you have a reason not to.

## Redacted

Remove personal data about end users and third parties before you send the text. Keep everything
the check needs: the talent's name, the scene, the product, the words to be spoken.

| Replace | With |
| - | - |
| Email addresses | `[email]` |
| Phone numbers | `[phone]` |
| Street addresses | `[address]` |
| Payment card and bank account numbers | `[card]` |
| Government ID numbers | `[id_number]` |
| Names of private people who are not talent | `[person]` |

For example, "A birthday message from Maya Okafor to my son Tom Ellis at 14 Birch Lane" becomes
"A birthday message from Maya Okafor to my son \[person] at \[address]".

<CodeGroup>
  ```bash cURL theme={null}
  curl https://app.reflections.ai/v1/checks \
    -H "Authorization: Bearer rk_test_…" \
    -H "Reflections-Version: 2026-10-15" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{
      "inputs": [{ "role": "script", "text": "A birthday message from Maya Okafor to my son [person] at [address]" }],
      "use": {
        "modality": "speech", "kind": "impersonation", "purpose": "personal",
        "commercial": false, "channels": ["private"], "territories": ["US"]
      },
      "end_user": { "id": "usr_48213" },
      "execution": { "provider": "example-voice-provider", "model": "tts-2", "candidates": 1 },
      "prompt_handling": { "mode": "redacted", "retention": "none" }
    }'
  ```

  ```typescript TypeScript theme={null}
  const check = await fetch("https://app.reflections.ai/v1/checks", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.REFLECTIONS_KEY}`,
      "Reflections-Version": "2026-10-15",
      "Idempotency-Key": crypto.randomUUID(),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      inputs: [{ role: "script", text: "A birthday message from Maya Okafor to my son [person] at [address]" }],
      use: {
        modality: "speech", kind: "impersonation", purpose: "personal",
        commercial: false, channels: ["private"], territories: ["US"],
      },
      end_user: { id: "usr_48213" },
      execution: { provider: "example-voice-provider", model: "tts-2", candidates: 1 },
      prompt_handling: { mode: "redacted", retention: "none" },
    }),
  }).then((r) => r.json());
  ```

  ```python Python theme={null}
  import os, uuid, requests

  check = requests.post(
      "https://app.reflections.ai/v1/checks",
      headers={
          "Authorization": f"Bearer {os.environ['REFLECTIONS_KEY']}",
          "Reflections-Version": "2026-10-15",
          "Idempotency-Key": str(uuid.uuid4()),
      },
      json={
          "inputs": [{"role": "script", "text": "A birthday message from Maya Okafor to my son [person] at [address]"}],
          "use": {
              "modality": "speech", "kind": "impersonation", "purpose": "personal",
              "commercial": False, "channels": ["private"], "territories": ["US"],
          },
          "end_user": {"id": "usr_48213"},
          "execution": {"provider": "example-voice-provider", "model": "tts-2", "candidates": 1},
          "prompt_handling": {"mode": "redacted", "retention": "none"},
      },
  ).json()
  ```
</CodeGroup>

Keep the mapping from placeholders to values on your side; Reflections never receives it. The
`request_digest` covers the text exactly as you sent it, so in this mode it covers the redacted
form. See [Bind the request](/build/binding-the-request).

**Cost:** a rule that depends on what you removed cannot be checked at the check. The generation
check still sees the output itself, and the transcript of a speech output, so rules about what was
made are still checked there.

## Withheld

Send no text at all. Send each text input with its `role` and the `sha256` of its UTF-8 bytes, with
`media_type: "text/plain"`, in place of `text`, and name each talent the request invokes in
`talent`. The planned protocol also accepts media files and URLs with digests. For the prompt
"Maya Okafor holding our new trail shoe on a rocky ridge at sunrise", its check body is:

<Note>
  The file reference below is planned and unsupported in test mode. The sandbox accepts media
  `sha256` and `media_type` as digest metadata only; it never fetches URLs, resolves talent from
  media or evaluates its content. Use the [quickstart](/quickstart) for a supported check.
</Note>

```json theme={null}
{
  "talent": ["tal_9t0wxyhk5zba2q8v1m3n7p4r6s"],
  "inputs": [
    { "role": "prompt", "sha256": "5e7eac730e81f9e8d45a228b4d8b4b7fdf028f36bf3a598a58633b7b5895e29f", "media_type": "text/plain" },
    { "role": "reference", "file": "file_7h3k9m2p4q6r8s1t3v5w7x9yza" }
  ],
  "use": {
    "modality": "image", "kind": "depiction", "purpose": "advertising",
    "commercial": true, "channels": ["social"], "territories": ["US"]
  },
  "execution": { "provider": "example-image-provider", "model": "image-model-3", "candidates": 2 },
  "prompt_handling": { "mode": "withheld" }
}
```

The digest then binds the exact text without Reflections seeing it: each text input enters the
`request_digest` as `{ "role", "sha256", "media_type" }`, like a media input.

**Cost:**

* Reflections cannot find talent by name in text it never receives. Send `talent` explicitly, and
  match prompts on your side with the [name index](/build/resolving-talent) so you know when to.
* Rules that need the text, such as "Do not imply she endorses any product other than the one
  shown", are checked on the output instead. You pay for a generation that may then be denied.
* Indirect references in text are never resolved, because the check never reads the text. Outputs
  are not screened for them either: send `talent` for every person the request means.

`withheld` is a choice for the platform to make. The decisions stay exact about what was checked:
the receipt never claims Reflections read the prompt.

## Retention

Reflections deletes prompt text as soon as it can:

| Data | Kept |
| - | - |
| Prompt text on `allow` | Deleted once the check is decided. The receipt keeps the `request_digest`. |
| Prompt text on `deny` or `escalate` | 30 days, for review and disputes |
| Prompt text with `prompt_handling.retention: "none"` | Deleted as soon as the check is decided, whatever the decision |
| End-user HMACs | 13 months |

With `retention: "none"`, a reviewer of an escalated check cannot read the prompt later, and a
dispute about a `deny` has only the digest to go on. The [privacy](/concepts/privacy) page has the
full retention table, including outputs and receipts.

## End users and metadata

* `end_user.id` is a stable ID scoped to your platform, such as `usr_48213`. Never send an email
  address, a phone number or a name. Reflections stores only an HMAC of it.
* `end_user.type` is `consumer` (the default) or `business`.
* `metadata` is for your own references. Never put personal data in it.

For prompts and outputs, Reflections processes data on your behalf under a data processing
agreement. For talent identity data, such as face and voice templates, Reflections is the
controller, acting for the talent.

## Related

<Columns cols={2}>
  <Card title="Privacy" icon="lock" href="/concepts/privacy">
    What is sent, what is kept, and for how long.
  </Card>

  <Card title="Bind the request" icon="link" href="/build/binding-the-request">
    How the digest binds what the model receives.
  </Card>

  <Card title="Resolve talent" icon="magnifying-glass" href="/build/resolving-talent">
    Explicit IDs and the local name index.
  </Card>

  <Card title="Privacy in the Standard" icon="book" href="/standard/privacy">
    Data minimization requirements on both sides.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.