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

# C2PA assertion

> The ai.reflections.license assertion that carries a receipt inside an output's C2PA manifest.

An allowed generation returns `c2pa`: an assertion to add to the output's
[C2PA](https://c2pa.org/specifications/) manifest before you deliver it. It carries the signed
receipt, so anyone who reads the manifest can verify the license decision without asking you.

You stay the C2PA claim signer for your own output. The receipt inside the assertion is signed by
Reflections, so it verifies independently of your signature.

## Bind the receipt to your signer

A receipt is public, so anyone can copy the assertion into a manifest for other content. To stop
that, send `c2pa_signer` when you [create the generation](/api-reference/generations/create-a-generation):

```json theme={null}
{ "c2pa_signer": { "thumbprint": "sha256:5d2a8c0e4b6f1a3c5e7d9b0f2a4c6e8d0b2f4a6c8e0d2b4f6a8c0e2d4b6f8a1c" } }
```

`thumbprint` is `sha256:` and the lowercase hex SHA-256 of the DER encoding of the end-entity
certificate that will sign the output's C2PA claim. Reflections signs it as `tlp.c2pa_signer` as
given, without checking it against a certificate. A verifier that reads the manifest compares it
with the certificate that signed the manifest and can reject a mismatch; a mismatch can also mean
a rotated or misdeclared certificate. Without
it, the assertion proves a decision was made, not that this file is the one decided
([TLP-RCP-16](/standard/receipts#binding-to-a-c2pa-claim-signer)). Rotate the certificate only for
outputs submitted after the change: the thumbprint is fixed in each receipt.

## The assertion

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

| Field | Type | Value |
| - | - | - |
| `label` | string | Always `ai.reflections.license`. |
| `data.receipt` | string | The receipt JWS: the same compact JWS, `typ` `tlp-receipt+jwt`, as the [receipt](/api-reference/formats/receipt)'s `jws`. Not the receipt ID. |
| `data.verify_url` | string | The public human receipt page, `https://app.reflections.ai/r/{receipt_id}`. |

`ai.reflections.license` is an entity-specific assertion label, in the reverse-domain form C2PA
uses for assertions outside its own `c2pa.` namespace. Copy `c2pa` from the generation as it is:
put `label` in the assertion's label and `data` in its data. Your C2PA library encodes `data` as
CBOR when it writes the manifest.

The generation returns `c2pa` only when `decision` is `allow`: in the create response for images,
text and speech up to 60 seconds, and in [`generation.allowed`](/api-reference/webhooks/generation-allowed) or
[`generation.released`](/api-reference/webhooks/generation-released) for outputs decided later.
It is `null` otherwise.

## Where it sits in the manifest

Add two assertions to the manifest you sign for the output:

1. A `c2pa.actions` assertion with a `c2pa.created` action whose `digitalSourceType` is the IPTC
   term for generated media,
   `http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia`. This says the output
   was made by a model. Tools that write C2PA 2.x manifests use the label `c2pa.actions.v2`; the
   action and the source type are the same.
2. The `ai.reflections.license` assertion, exactly as the generation returned it.

A manifest definition for the line of speech in Maya Okafor's voice from the
[receipt example](/api-reference/formats/receipt#example-payload), as Northlight signs it:

```json theme={null}
{
  "claim_generator_info": [{ "name": "Northlight", "version": "4.2.0" }],
  "title": "maya-okafor-trail-season.wav",
  "format": "audio/wav",
  "assertions": [
    {
      "label": "c2pa.actions",
      "data": {
        "actions": [
          {
            "action": "c2pa.created",
            "digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia"
          }
        ]
      }
    },
    {
      "label": "ai.reflections.license",
      "data": {
        "receipt": "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0…",
        "verify_url": "https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
      }
    }
  ]
}
```

Sign the manifest with your own C2PA certificate and embed it in the file. Then show the
disclosure text from the `disclosure` obligation, and deliver.

<Note>
  Embedding the manifest changes the file's bytes, so the delivered file's SHA-256 differs from the
  receipt's `artifact_sha256`. Verification finds the receipt by the manifest when it survives.
  Fingerprint lookup, for a file whose manifest a platform stripped, is planned; until then, keep the
  receipt ID with the file. A fingerprint never exists for an `attested` output, because Reflections
  did not receive its bytes.
</Note>

## Reading it

A verifier that finds `ai.reflections.license` in a manifest:

1. Validates the manifest with its C2PA tool, which proves the file is what the claim signer
   signed.
2. Verifies `data.receipt` against the [JWKS](/api-reference/formats/discovery#jwks), as described
   in [Receipt](/api-reference/formats/receipt#verify-a-receipt).
3. Compares `tlp.c2pa_signer.thumbprint`, when present, with the SHA-256 of the claim signer
   certificate's DER, and rejects the assertion when they differ. A receipt without it is unbound.
4. Reads the live status at [`GET /v1/receipts/{receipt_id}`](/api-reference/receipts/retrieve-a-receipt),
   or opens `data.verify_url`.

Or it sends the whole manifest store, base64-encoded, as `manifest` to
[`POST /v1/verifications`](/api-reference/verifications/verify-content). The result reports the
claim `signer`, whether the assertion is present, whether its signature is valid, and the receipt.
Manifest verification is planned: neither mode reads a manifest yet, so a verifier checks the
signer binding itself.

## Related

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

  <Card title="C2PA in the Standard" icon="book" href="/standard/interop/c2pa">
    Manifest and assertion placement, and soft bindings.
  </Card>
</Columns>


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