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

# Image and video platforms

> Where the check and the generation check sit in an image or video generation pipeline, and what each stage must do.

<Note>
  The initial live image implementation below is deployed, subject to signing activation and
  production acceptance. The rest of this guide describes the broader planned contract.
  The sandbox supports fixture checks and generations; test decisions do not authorize real use.
  Start with the [runnable quickstart](/quickstart) and [sandbox support matrix](/sandbox).
</Note>

## Initial live image implementation

This path is for a licensee using its own newly signed license for commercial advertising or
branded content. It requires explicit `externalCreation: "images.v1"` and
`externalCreationPostRevocation: "retain"` terms. Existing signatures grant neither by omission.
Protected activation of the live signer must follow its public key's 30-day publication interval.
Deployment, signing activation, supplier processing and independent live acceptance remain
separate [qualification requirements](/production/conformance#initial-live-image-implementation).

Retain the issued and accepted license document for its signed scope. Live license reads return
the current revision and terms digest with a partial scope; omitted channels or territories grant
nothing. The initial live API does not export the full signed revision or the talent's original
signature. Match the license revision and digest to Reflections' signed decision receipts; this
does not independently verify the talent's original signature.

1. **Check the effective request.** Send one explicit owned `license`, text inputs totaling at
   most 64 KiB of UTF-8, image `depiction`, `commercial: true`, purpose `advertising` or
   `branded_content`, and the intended channels and territories. Every value must match the
   signed scope; only signed `WW` grants worldwide use. Set `execution.provider`,
   `execution.model`, `execution.candidates: 1` and `on_escalate: "deny"`.
2. **Wait for the check.** Persist the body and its `Idempotency-Key`. While evaluation is pending,
   the response is `202` with `status: "checking"`; retry with the same body and key after
   `Retry-After`. Continue only after `decision: "allow"`, and meet every obligation. A denial
   does not permit generation.
3. **Generate one image in your tool.** Use the checked request and declared provider and model
   and leave enough time to finish and submit before `authorization.expires_at`. Starting the
   provider job before expiry is not sufficient. `job_id` is optional and may be supplied after
   the provider starts.
   Reflections does not render the image or fetch provider output.
4. **Submit the exact output.** Send one inline still PNG of at most 7 MiB (7,340,032 decoded
   bytes), its lowercase SHA-256, `candidate_index: 0`, and matching provider/model. The JSON
   body may be at most 10 MiB. Use a new persisted idempotency key for this operation. The same
   caller key must hold both `checks:write` and `generations:write`. Send the allowed `check` ID;
   Reflections reads its stored authorization token, so no separate token field is submitted.
   The first successful submission must arrive before `authorization.expires_at`; otherwise it
   fails with `409 check_expired`.
5. **Poll and keep the output private.** A successful POST returns `202` with the accepted
   generation. Its retries always return that original response. GET the generation for
   `checking`, `held`, `released`, `denied` or `expired`. An image that passes evaluation and
   retains authority moves to talent review; only the talent's actual release permits
   `decision: "allow"`. Denied and expired images stay private.
6. **Verify the receipt before delivery.** Follow the signed obligations for provenance and
   disclosure. Receipt retrieval and JSON verification by live receipt ID or JWS are public;
   lookup by artifact digest requires the owning account's live key. Public responses exclude
   private request metadata.

```mermaid theme={null}
flowchart LR
    A[Owned license and text request] --> B[Check]
    B -->|allow| C[Generate one PNG]
    B -->|deny| X[Stop]
    C --> D[Submit exact bytes]
    D --> E[202 accepted]
    E --> F[Poll generation]
    F -->|checking or held| F
    F -->|released and allow| G[Verify receipt and deliver]
    F -->|denied or expired| X
```

No reference-media inputs, talent/facet selection, personal or end-user use, reuse, request review
holds, delegated accounts, live lists, cancellation, withdrawal, revocation feeds, uploaded files,
video, OAuth or webhooks are supported in this path. A checksum without inline PNG bytes is
insufficient. Private details remain available while pending and for 24 hours after their terminal
retention boundary, then return `404`; signed receipts are kept separately for seven years.
Reflections-managed retention does not establish upstream provider deletion. See
[Privacy](/concepts/privacy).

## Broader image and video contract

The remaining sections include planned forms beyond the initial live implementation above.

An image or video platform calls Reflections at two points in its pipeline: a check after it has
built the request the model will receive, and a generation for every output before anyone sees
it. This guide places both calls, and the obligations between them, in a production pipeline.

```mermaid theme={null}
flowchart LR
    A[User request] --> B[Build the effective request]
    B --> C[Check]
    C -->|deny| X[Show reasons]
    C -->|escalate| W[Pending until check.resolved]
    C -->|allow| D[Generate with instructions and token]
    D --> E[Generation for each candidate]
    E -->|allow| F[Embed receipt, label, deliver]
    E -->|escalate| H[Hold, draft preview only]
    E -->|deny| Y[Discard]
```

## Decide whose license applies

Every check names one licensee and one platform.

| Who the output is for | Licensee | What you send |
| - | - | - |
| A brand's campaign on your platform | The brand | `Reflections-Account: acct_…` for the brand, after it connects your platform |
| Your own users' personal creations | Your platform, under a platform license | No `Reflections-Account` header |

A brand connects your platform through OAuth, and you receive `connection.created`. From then on,
checks you send with its account ID use its licenses. See
[Brands and agencies](/guides/brands-and-agencies) for the brand's side and
[Authentication](/api-reference/authentication) for the OAuth flow.

## Build the effective request

The check binds the request the model actually receives, so send it after your own prompt
handling, not before.

| Input `role` | Send |
| - | - |
| `prompt` | The user's words |
| `rewritten_prompt` | Your expansion of the prompt, if the model receives that instead |
| `system`, `negative_prompt` | Any text you add |
| `reference`, `mask` | Every image or clip the model receives, as a file ID or `sha256` with a `url` |

Upload references with `purpose: "reference"` and masks with `purpose: "mask"`. If your interface
has a cast picker, pass the chosen talent in `talent` and skip resolution. When a talent has
several facets, name one with `facet`. [Binding the request](/build/binding-the-request) covers
edits, image-to-video and multi-step pipelines.

When the license includes `material_access`, you can send the talent's own reference stills.
[`GET /v1/facets/{facet_id}/material`](/api-reference/facets/retrieve-licensed-material) returns
download URLs that expire after 5 minutes, each with its `sha256`. Send exactly those bytes, and
follow the obligations that come with them, such as `delete_material` and `no_training`.

## Check before you generate

Set `execution.candidates` to the number of outputs the model returns. One check covers them all,
and its authorization allows that many generations.

| Decision | In the pipeline |
| - | - |
| `allow` | Continue. Meet every obligation. |
| `deny` | Stop. Show `reasons[].sentence`. Offer the `remedy` to a licensee if there is one. |
| `escalate` | Stop. Show a pending state. Continue on `check.resolved` with `allow`, using the same request. |

Pass `on_escalate: "deny"` from interactive surfaces where a user is waiting. Batch and studio
workflows can leave the default, `hold`, and let a reviewer decide. See
[Handling escalations](/build/handling-escalations).

## Meet the obligations

Obligations are typed. Handle each one at the stage where it applies:

| Obligation | Stage | What your pipeline does |
| - | - | - |
| `generation_instructions` | Before the model | Add every instruction to the model's input |
| `generation_check` | After the model | Submit every output, or the `sample_rate` share when `required` is `sampled` |
| `hold_until_release` | After the generation | Keep clean bytes private until `generation.released` |
| `draft_watermark` | Before release | Mark any preview with a visible draft watermark |
| `c2pa_manifest` | Delivery | Embed the receipt as a C2PA assertion |
| `disclosure` | Delivery | Show `text` where `placement` says: `visible`, `metadata` or `both` |
| `attribution` | Delivery | Show the credit line `text` where the output appears |
| `no_training` | Always | Do not train on the `material` named |
| `delete_material` | After use | Delete the `material` named `within` the stated time |
| `usage_report` | After delivery | Report `units` `within` the stated time |

If a check returns an obligation type your code does not handle, treat it as unmet and do not
generate. [Obligations](/concepts/obligations) describes each one.

## Generate

Send the model the request you checked, plus the instructions. Send your provider
`authorization.token` so it can verify the request offline, and start the job before
`authorization.expires_at`. A provider that verifies tokens rejects one issued for a different
model or already used up. See [Model providers](/guides/model-providers).

## Submit every output

Each output becomes a generation that names its `check` and `candidate_index`, with the SHA-256
of its bytes. **Today**, send the bytes inline as `artifact.data` (base64), at most 7 MiB decoded in a
10 MiB JSON body, as the [quickstart](/quickstart) does. The sandbox returns the decision in the
response; the [initial live implementation](#initial-live-image-implementation) returns `202` and you
poll. **Planned:** upload larger files with [`POST /v1/files`](/api-reference/files/upload-a-file),
multipart up to 100 MB or a JSON upload URL up to 5 GB. Neither mode serves file uploads or fetches
URLs yet.

* **Images** return a decision in the sandbox response.
* **Video** returns `status: "checking"`. The decision arrives as `generation.allowed` or
  `generation.denied`. The p95 target is half the video's duration plus 5 seconds.
* **Held outputs** return `escalate` with `status: "held"` and wait for `generation.released`,
  `generation.denied` or `generation.expired`.

Read `findings` for what was checked on the bytes and `unchecked_terms` for talent-written rules
that could not be read: those outputs are delivered and the rule is recorded as unchecked.
Protected attributes, such as `identity.samePerson`, never pass unchecked. See
[Submitting outputs](/build/submitting-outputs) and
[Generation checks](/concepts/generation-checks).

An output is checked only for the talent its check covered, so send every reference image your user
uploads as a check input: that is how a photo of a protected talent is matched.

## Deliver

Embed `c2pa` in the output's C2PA manifest with the standard `c2pa.actions` entry, show the
disclosure and any attribution, then deliver. Your platform signs the manifest; the receipt inside
is signed by Reflections. See [Embedding provenance](/build/embedding-provenance).

## When Reflections cannot be reached

Fail closed for named talent. On `503 service_unavailable`, generate nothing for a named talent
unless you already hold an unexpired authorization, and then only within its `max_generations`.
Retry with the same `Idempotency-Key`. A request that names no talent, matches nothing in your
name index and carries no reference may still run. See [Failure modes](/concepts/failure-modes).

## What can go wrong

| Response | Cause | What to do |
| - | - | - |
| `403 account_not_connected` | The brand has no active connection with your platform | Ask the brand to connect again |
| `409 generation_already_submitted` | This candidate already has a generation | Read the existing one |
| `409 authorization_consumed` | More outputs than `max_generations` | Run a new check for the extra outputs |
| `409 check_expired` | The authorization expired before use | Run a new check |
| `422 artifact_digest_mismatch` | The bytes do not match `sha256` | Hash the bytes you upload |

## Related

<Columns cols={2}>
  <Card title="Image quickstart" icon="image" href="/quickstarts/image">
    Candidates, instructions, a held output and a receipt, in test mode.
  </Card>

  <Card title="Video integration design" icon="video" href="/quickstarts/video">
    Asynchronous checks and large uploads.
  </Card>

  <Card title="Handling revocations" icon="ban" href="/build/handling-revocations">
    What to stop, purge and acknowledge when consent narrows.
  </Card>

  <Card title="Production checklist" icon="list-check" href="/production/checklist">
    What a live integration must do.
  </Card>
</Columns>


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