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

# Authorize a client

> **Planned contract — unavailable in test and live modes.** This operation is a protocol reference, not a callable endpoint. Start with the [working sandbox quickstart](/quickstart).

The page where a person approves an OAuth client. Send the person's browser here; your
server never calls it. A licensee approves a platform's
[connection](/api-reference/authentication#connect-a-licensee-with-oauth), and an agent's
user approves an [MCP client](/api-reference/mcp/overview). The person signs in to
Reflections, chooses test or live mode, and sees the client's name and the scopes it asks
for.

Reflections then redirects to `redirect_uri`. After an approval the query carries `code`,
`state` and `iss`; after a decline it carries `error=access_denied`, `state` and `iss`.
Check that `state` matches and that `iss` is `https://app.reflections.ai`. A code works once
and expires after 10 minutes. A platform redeems it at
[`POST /v1/connections`](/api-reference/connections/create-a-connection) with its secret
key; every other client redeems it at
[`POST /oauth/token`](/api-reference/oauth/create-an-access-token).

PKCE with `S256` is required for every client. When `client_id` is unknown or
`redirect_uri` is not one of the client's registered URIs, Reflections shows an error page
and does not redirect, so a code never reaches an address the client did not register.

Public: the person signs in on the page, and no key is sent.




## OpenAPI

````yaml /api-reference/openapi.yaml get /oauth/authorize
openapi: 3.1.0
info:
  title: Reflections Talent API
  version: '2026-10-15'
  summary: The license server for a person's name, likeness and voice in generative AI.
  description: >
    This document defines the target Talent API contract. Each operation
    declares its current

    test and live availability. Test mode serves a limited fictional sandbox.
    Live keys support

    account details and reading the caller's own licenses. The initial live
    image check,

    submission and receipt implementation is deployed, but requires separate
    live signing

    activation and production acceptance. Start at
    https://docs.reflections.ai/quickstart for test mode.


    The target API lets any product that can generate a real person check
    whether a use is licensed,

    verify the output it made, prove that verification to anyone downstream,
    report usage, and

    honor revocations.


    Protected requests use a secret key in the `Authorization` header. The
    target contract defines test keys

    (`rk_test_…`) and live keys (`rk_live_…`) use the same base URL; the key
    decides the mode.


    A decision is never an error. `deny` and `escalate` are `200` responses that
    carry a decision.

    Errors use RFC 9457 problem details.
  contact:
    name: Reflections developer support
    url: https://docs.reflections.ai/production/support
    email: developers@reflections.ai
servers:
  - url: https://app.reflections.ai/v1
    description: >-
      Fictional test sandbox and conditional live support; availability and
      activation are separate
security:
  - SecretKey: []
tags:
  - name: Account
    description: The account that owns the calling key.
  - name: Talent
    description: >-
      People whose name, likeness and voice are protected and licensed through
      Reflections.
  - name: Facets
    description: >-
      The parts of a talent's identity a license can cover, such as a voice or a
      likeness.
  - name: Resolutions
    description: Find which talent a prompt, image or voice sample invokes.
  - name: Licenses
    description: Signed licenses and their revisions.
  - name: License requests
    description: Ask a talent for a new license or a wider one.
  - name: Connections
    description: A licensee's permission for a platform to use its licenses.
  - name: Files
    description: References and outputs uploaded for checks and generations.
  - name: Checks
    description: Decide whether a use may proceed, before anything is generated.
  - name: Generations
    description: Check an output against the license its check relied on.
  - name: Sessions
    description: Authorize live voice and video with short-lived tokens and sampled checks.
  - name: Receipts
    description: Signed, portable proof of a decision.
  - name: Verifications
    description: Verify a file, manifest or receipt.
  - name: Revocations
    description: Every narrowing of consent, and the platform's acknowledgement of it.
  - name: Usage records
    description: Report usage for settlement and audit.
  - name: Statements
    description: Monthly amounts owed under a license, reconciled against observed usage.
  - name: Mandates
    description: A representative's authority to act for a talent, and its powers.
  - name: Escalations
    description: >-
      The review queue. Checks and held outputs waiting for the talent's side to
      decide.
  - name: License drafts
    description: Terms prepared for a talent's signature. Only a person signs.
  - name: Webhook endpoints
    description: Where Reflections sends events.
  - name: Events
    description: The record of everything that happened to your objects.
  - name: Test helpers
    description: Act as a talent or reviewer in test mode.
  - name: Discovery
    description: The public discovery document and signing keys. Neither needs a key.
  - name: OAuth
    description: >
      Authorization for connections, MCP clients and RSL clients, and the
      metadata that describes it.
paths:
  /oauth/authorize:
    get:
      tags:
        - OAuth
      summary: Authorize a client
      description: >
        **Planned contract — unavailable in test and live modes.** This
        operation is a protocol reference, not a callable endpoint. Start with
        the [working sandbox quickstart](/quickstart).


        The page where a person approves an OAuth client. Send the person's
        browser here; your

        server never calls it. A licensee approves a platform's

        [connection](/api-reference/authentication#connect-a-licensee-with-oauth),
        and an agent's

        user approves an [MCP client](/api-reference/mcp/overview). The person
        signs in to

        Reflections, chooses test or live mode, and sees the client's name and
        the scopes it asks

        for.


        Reflections then redirects to `redirect_uri`. After an approval the
        query carries `code`,

        `state` and `iss`; after a decline it carries `error=access_denied`,
        `state` and `iss`.

        Check that `state` matches and that `iss` is
        `https://app.reflections.ai`. A code works once

        and expires after 10 minutes. A platform redeems it at

        [`POST /v1/connections`](/api-reference/connections/create-a-connection)
        with its secret

        key; every other client redeems it at

        [`POST /oauth/token`](/api-reference/oauth/create-an-access-token).


        PKCE with `S256` is required for every client. When `client_id` is
        unknown or

        `redirect_uri` is not one of the client's registered URIs, Reflections
        shows an error page

        and does not redirect, so a code never reaches an address the client did
        not register.


        Public: the person signs in on the page, and no key is sent.
      operationId: authorizeClient
      parameters:
        - name: response_type
          in: query
          required: true
          description: Always `code`.
          example: code
          schema:
            type: string
            enum:
              - code
        - name: client_id
          in: query
          required: true
          description: >
            The client's ID: a platform's `platform.client_id` from

            [`GET /v1/account`](/api-reference/account/retrieve-your-account), a
            `client_id` from

            [`POST /oauth/register`](/api-reference/oauth/register-a-client), or
            the HTTPS URL of

            the client's metadata document.
          example: cl_064fvt404z82ymdspje0ggaztt
          schema:
            type: string
        - name: redirect_uri
          in: query
          required: true
          description: >-
            Where Reflections sends the person back. It must equal one of the
            client's registered redirect URIs.
          example: https://northlight.example/oauth/reflections/callback
          schema:
            type: string
            format: uri
        - name: scope
          in: query
          required: true
          description: >
            Space-separated scopes. A platform asks for

            [connection
            scopes](/api-reference/authentication#connect-a-licensee-with-oauth),
            and an

            MCP client for [MCP scopes](/api-reference/mcp/overview#scopes). Ask
            only for what you

            use.
          example: files:write checks:write generations:write usage:write
          schema:
            type: string
        - name: state
          in: query
          required: true
          description: >
            An unguessable value you keep with the person's session. It comes
            back unchanged;

            reject a redirect whose `state` you did not send.
          example: Rk0OaU_G8bRVUyv9
          schema:
            type: string
            minLength: 16
            maxLength: 512
        - name: code_challenge
          in: query
          required: true
          description: >-
            The PKCE challenge, `BASE64URL(SHA-256(code_verifier))` without
            padding.
          example: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
          schema:
            type: string
            minLength: 43
            maxLength: 43
        - name: code_challenge_method
          in: query
          required: true
          description: Always `S256`.
          example: S256
          schema:
            type: string
            enum:
              - S256
        - name: resource
          in: query
          required: false
          description: >
            The resource the token will be used at, as RFC 8707 defines. MCP
            clients send

            `https://app.reflections.ai/mcp`. Platforms leave it out.
          schema:
            type: string
            format: uri
      responses:
        '302':
          description: >
            Redirects to `redirect_uri`. After an approval the query carries
            `code`, `state` and

            `iss`. After a decline or a request Reflections cannot accept, it
            carries `error`, an

            optional `error_description`, `state` and `iss`. `error` is
            `access_denied` (the person

            declined), `invalid_scope` (a scope the client may not ask for),

            `invalid_request` (a missing or malformed parameter, including
            PKCE),

            `unsupported_response_type`, `server_error` or
            `temporarily_unavailable`.
          headers:
            Location:
              description: The redirect URI with the result in its query.
              schema:
                type: string
                format: uri
                example: >-
                  https://northlight.example/oauth/reflections/callback?code=ac_Jf3k9QmZ2vX8pT4wR7nY1bL6&state=Rk0OaU_G8bRVUyv9&iss=https%3A%2F%2Fapp.reflections.ai
        '400':
          description: >
            `client_id` is unknown, or `redirect_uri` is not registered for it.
            Reflections shows

            an error page and does not redirect.
          content:
            text/html:
              schema:
                type: string
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
        '503':
          $ref: '#/components/responses/Unavailable'
      security: []
      servers:
        - url: https://app.reflections.ai
      x-codeSamples:
        - lang: bash
          label: URL
          source: >
            # Send the person's browser to this URL.

            AUTHORIZE_URL='https://app.reflections.ai/oauth/authorize?response_type=code&client_id=cl_064fvt404z82ymdspje0ggaztt&redirect_uri=https%3A%2F%2Fnorthlight.example%2Foauth%2Freflections%2Fcallback&scope=files%3Awrite+checks%3Awrite+generations%3Awrite+usage%3Awrite&state=Rk0OaU_G8bRVUyv9&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256'
        - lang: typescript
          label: TypeScript
          source: >
            const authorizeUrl = new
            URL("https://app.reflections.ai/oauth/authorize");

            authorizeUrl.search = new URLSearchParams({
              "response_type": "code",
              "client_id": "cl_064fvt404z82ymdspje0ggaztt",
              "redirect_uri": "https://northlight.example/oauth/reflections/callback",
              "scope": "files:write checks:write generations:write usage:write",
              "state": "Rk0OaU_G8bRVUyv9",
              "code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
              "code_challenge_method": "S256"
            }).toString();


            // Send the person's browser to authorizeUrl.toString().

            console.log(authorizeUrl.toString());
        - lang: python
          label: Python
          source: >
            from urllib.parse import urlencode


            authorize_url = "https://app.reflections.ai/oauth/authorize" + "?" +
            urlencode({
                "response_type": "code",
                "client_id": "cl_064fvt404z82ymdspje0ggaztt",
                "redirect_uri": "https://northlight.example/oauth/reflections/callback",
                "scope": "files:write checks:write generations:write usage:write",
                "state": "Rk0OaU_G8bRVUyv9",
                "code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
                "code_challenge_method": "S256",
            })


            # Send the person's browser to authorize_url.

            print(authorize_url)
        - lang: go
          label: Go
          source: |
            package main

            import (
                "fmt"
                "net/url"
            )

            func main() {
                query := url.Values{
                    "response_type": {"code"},
                    "client_id": {"cl_064fvt404z82ymdspje0ggaztt"},
                    "redirect_uri": {"https://northlight.example/oauth/reflections/callback"},
                    "scope": {"files:write checks:write generations:write usage:write"},
                    "state": {"Rk0OaU_G8bRVUyv9"},
                    "code_challenge": {"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"},
                    "code_challenge_method": {"S256"},
                }
                authorizeURL := "https://app.reflections.ai/oauth/authorize" + "?" + query.Encode()
                // Send the person's browser to authorizeURL.
                fmt.Println(authorizeURL)
            }
components:
  responses:
    RateLimited:
      description: Too many requests.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.reflections.ai/errors/rate_limited
            title: Too many requests
            status: 429
            code: rate_limited
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    ServerError:
      description: Something failed on our side. Retry with the same idempotency key.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unavailable:
      description: >
        Reflections is temporarily unavailable. Do not generate a named talent
        without a valid

        authorization. Retry with the same idempotency key.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  headers:
    RequestId:
      description: Identifies this request. Include it when you contact support.
      schema:
        type: string
        example: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    RetryAfter:
      description: Seconds to wait before retrying.
      schema:
        type: integer
  schemas:
    Problem:
      type: object
      description: An RFC 9457 problem detail. Every error has this shape.
      required:
        - type
        - title
        - status
        - code
        - request_id
      properties:
        type:
          type: string
          format: uri
          description: A URL for this error, under `https://docs.reflections.ai/errors/`.
        title:
          type: string
          description: A short summary of the error.
        status:
          type: integer
          description: The HTTP status.
        detail:
          type: string
          description: What happened in this request.
        code:
          $ref: '#/components/schemas/ErrorCode'
          description: The stable error code. Branch on it, then on `status`.
        param:
          type: string
          description: The field at fault, as a path such as `use.territories[1]`.
        request_id:
          type: string
          description: >
            `req_…`, the same value as the `Request-Id` header. Include it when
            you contact support.
        doc_url:
          type: string
          format: uri
          description: A link to the documentation for this error.
    ErrorCode:
      type: string
      description: A stable error code. See the error code catalog.
      enum:
        - invalid_request
        - parameter_missing
        - parameter_invalid
        - unsupported_modality
        - unsupported_media_type
        - media_unreadable
        - version_unsupported
        - authorization_code_invalid
        - authentication_required
        - invalid_api_key
        - token_invalid
        - insufficient_scope
        - account_not_connected
        - mandate_required
        - livemode_mismatch
        - live_not_activated
        - platform_not_permitted
        - resource_not_found
        - idempotency_key_in_use
        - generation_already_submitted
        - authorization_consumed
        - check_not_allowed
        - check_expired
        - escalation_closed
        - license_draft_closed
        - invalid_state_transition
        - session_not_active
        - payload_too_large
        - idempotency_key_reused
        - artifact_digest_mismatch
        - rate_limited
        - internal_error
        - service_unavailable
        - evaluation_timeout
  securitySchemes:
    SecretKey:
      type: http
      scheme: bearer
      description: >
        Your secret key, `rk_test_…` or `rk_live_…`, sent as `Authorization:
        Bearer <key>`. Keep it

        on your server. Restricted keys carry only the scopes you give them.

````

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