Skip to main content
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 and sandbox support matrix.

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. 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, retry 409 idempotency_key_in_use 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.
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.

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.

Decide whose license applies

Every check names one licensee and one platform. 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 for the brand’s side and 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. 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 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 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. 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.

Meet the obligations

Obligations are typed. Handle each one at the stage where it applies: If a check returns an obligation type your code does not handle, treat it as unmet and do not generate. 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.

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 does. The sandbox returns the decision in the response; the initial live implementation returns 202 and you poll. Planned: upload larger files with POST /v1/files, 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 and 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.

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.

What can go wrong

Image quickstart

Candidates, instructions, a held output and a receipt, in test mode.

Video integration design

Asynchronous checks and large uploads.

Handling revocations

What to stop, purge and acknowledge when consent narrows.

Production checklist

What a live integration must do.