> ## 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.

# Provenance

> Signed receipts, the C2PA assertion, fingerprints and watermarks, and how anyone verifies an output.

<Note>
  Sandbox and protocol reference. Signed test receipts and exact-digest lookup are available.
  Hosted C2PA parsing, fingerprints, watermarks and production revocation status remain planned.
  A test receipt grants no rights over real talent.
  Start with the [runnable quickstart](/quickstart) and [sandbox support matrix](/sandbox).
</Note>

Every decision produces a signed **receipt**. The receipt of an allowed generation goes into the
output's C2PA manifest, so the file carries the proof. Anyone can verify a receipt offline
against Reflections' public keys, or look it up to read its live status.

## Receipts

A receipt is a compact JWS signed with ES256, with `typ` `tlp-receipt+jwt` and no expiry. It
records:

| Claim | Meaning |
| - | - |
| `jti`, `sub` | The receipt ID, and the check or generation it records |
| `tlp.kind`, `tlp.decision` | `check` or `generation`, and the decision |
| `tlp.assurance` | `observed` or `attested`, below |
| `tlp.talent`, `tlp.licenses` | Who, and for each talent's license the exact signed revision and its terms digest |
| `tlp.request_digest` | The request that was checked |
| `tlp.artifact_sha256` | The output's bytes, on generation receipts |
| `tlp.use`, `tlp.obligations` | The use and what it required |
| `tlp.platform`, `tlp.licensee` | The parties |

The same receipt is also issued as a COSE\_Sign1 structure (alg ES256, `-7`) with the same claims as
its JSON payload, for embedding where COSE is expected. The full format is on
[Receipt](/api-reference/formats/receipt).

### Signing keys

Receipts are verified against the keys at `https://app.reflections.ai/.well-known/jwks.json`:
EC P-256 keys with `kid` values such as `rfl-2026-10-docs3` (live) and `rfl-test-2026-10-docs3` (test). A new key
is published 30 days before it signs anything, retired keys stay published so old receipts keep
verifying, and a `kid` is never reused.

### Live status

A receipt's signature proves what was decided. Its `use_status` says what use is permitted now:

| `use_status` | Meaning |
| - | - |
| `permitted` | Use within the receipt's `permitted_use` |
| `ceased` | No new placements, after a revocation |
| `withdrawn` | Take it down |
| `expired` | The use window ended |

Read it with [`GET /v1/receipts/{receipt_id}`](/api-reference/receipts/retrieve-a-receipt), with any
key or with none at the public rate limit. The current endpoint returns JSON at
`https://app.reflections.ai/v1/receipts/{receipt_id}`. A receipt stays valid evidence that an output was
licensed when it was made, even after a revocation changes its `use_status`.

## The C2PA assertion

An allowed generation returns a `c2pa` object:

```json theme={null}
{
  "label": "ai.reflections.license",
  "data": {
    "receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0…",
    "verify_url": "https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
  }
}
```

Add it to the output's C2PA manifest as an assertion under `label`, along with the standard
`c2pa.actions` assertion recording the IPTC digital source type `trainedAlgorithmicMedia`. Your
platform stays the C2PA claim signer for its own output. Because the receipt inside is signed by
Reflections, it verifies independently of your signature. See
[Embedding provenance](/build/embedding-provenance) and the
[C2PA specifications](https://c2pa.org/specifications/).

## When metadata is stripped

A C2PA manifest survives only where the file keeps its metadata, and many upload pipelines strip it.
Verification by file covers that: Reflections matches the file by its exact digest first, then by
fingerprint, so it still finds the receipt after metadata is removed or the file is re-encoded.
Reflections keeps each allowed output's `sha256` and fingerprint for the license term plus 3 years.

If you also apply a watermark, register it on the generation with
`watermark: { "algorithm": "…", "id": "…" }` so verification can join the two. Reflections does
not require any particular watermark.

## Verification

[`POST /v1/verifications`](/api-reference/verifications/verify-content) takes exactly one of a
`receipt` (ID or JWS), a C2PA `manifest`, a `url`, a `sha256`, a `fingerprint`, or the file itself.
These are the protocol methods. The current sandbox accepts only `receipt` or `sha256`, and a test
receipt needs a test key; see the [verification table](/api-reference/authentication#endpoints-that-need-no-key). Digest lookup is limited to your account; a known receipt ID can be read
without a key at `GET /v1/receipts/{receipt_id}`.

| `result` | Meaning |
| - | - |
| `verified` | A valid receipt matches |
| `not_found` | Nothing matches. This says nothing about whether the content is licensed |
| `invalid` | A receipt or manifest is present and fails verification |

`method` says how the match was made: `receipt`, `manifest`, `digest`, `fingerprint` or
`watermark`. `match.exact` says whether the bytes match the registered digest, and `manifest`
reports the C2PA claim `signer`, whether the assertion is present, and whether its signature is
valid. Test receipts verify only with a test key.

## Assurance

Every receipt states its `assurance`:

* `observed`: Reflections checked these bytes, or read these inputs.
* `attested`: Reflections recorded what you stated, such as text you sent `withheld`.

A receipt never claims Reflections inspected something it did not receive. See
[What we enforce](/concepts/what-we-enforce).

## Example: verifying a voice line

A podcast host receives an audio file that claims to be a licensed line in Maya Okafor's voice. The
host reads the receipt ID from the file's manifest and verifies it:

<CodeGroup>
  ```bash cURL theme={null}
  curl https://app.reflections.ai/v1/verifications \
    -H "Authorization: Bearer rk_test_…" \
    -H "Reflections-Version: 2026-10-15" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{ "receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy" }'
  ```

  ```typescript TypeScript theme={null}
  const verification = await fetch("https://app.reflections.ai/v1/verifications", {
    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({ receipt: "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy" }),
  }).then((r) => r.json());
  ```

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

  verification = requests.post(
      "https://app.reflections.ai/v1/verifications",
      headers={
          "Authorization": f"Bearer {os.environ['REFLECTIONS_KEY']}",
          "Reflections-Version": "2026-10-15",
          "Idempotency-Key": str(uuid.uuid4()),
      },
      json={"receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"},
  ).json()
  ```
</CodeGroup>

```json theme={null}
{
  "id": "vrf_3c5e7g9j1k3m5n7p9r1s3t5v7w",
  "object": "verification",
  "result": "verified",
  "method": "receipt",
  "receipt": {
    "id": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy",
    "object": "receipt",
    "kind": "generation",
    "subject": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
    "decision": "allow",
    "assurance": "observed",
    "talent": ["tal_9t0wxyhk5zba2q8v1m3n7p4r6s"],
    "licenses": [
      {
        "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
        "license": "lic_ba2q8v1m3n7p4r6s9t0wxyhk5z",
        "license_revision": "lrv_7p4r6s9t0wxyhk5zba2q8v1m3n",
        "terms_digest": "sha256:8e0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a"
      }
    ],
    "artifact_sha256": "3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d",
    "permitted_use": { "modality": "speech", "purpose": "branded_content", "channels": ["audio", "web"], "territories": ["US"], "ends_at": "2027-06-30T23:59:59Z" },
    "use_status": "permitted",
    "page_url": "https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
  }
}
```

The receipt is real, and it covers branded content on audio and the web in the US. A receipt ID
alone does not show that the host's file is the output the receipt describes; verify the file
itself to find out.

## Related

<Columns cols={2}>
  <Card title="Embedding provenance" icon="code" href="/build/embedding-provenance">
    Writing the assertion and the disclosure label.
  </Card>

  <Card title="Verifying content" icon="magnifying-glass" href="/build/verifying-content">
    Verification by receipt, manifest or file.
  </Card>

  <Card title="Distribution platforms" icon="upload" href="/guides/distribution-platforms">
    Verifying on upload and reading live status.
  </Card>

  <Card title="C2PA assertion" icon="receipt" href="/api-reference/formats/c2pa-assertion">
    The `ai.reflections.license` format.
  </Card>
</Columns>


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