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

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

Registers an OAuth client, as Dynamic Client Registration (RFC 7591) defines. MCP clients
call it on their own the first time they connect, so a person needs only the server's URL.

Sent without a key, it registers a public client: `token_endpoint_auth_method` must be
`none`, and the grants are `authorization_code` and `refresh_token`. A public client acts
for whoever signs in on the authorization page.

Sent with your secret key, it registers a confidential client that belongs to your account
and receives a `client_secret`, shown only in this response. Use one for an
[RSL](/standard/interop/rsl) client that requests `License` tokens with
`client_credentials`, or for a content host that checks them with
[`POST /oauth/introspect`](/api-reference/oauth/introspect-a-token). A `License` token
issued to it draws on your account's licenses.

A client can also skip registration and use the HTTPS URL of a client metadata document as
its `client_id`; Reflections reads the document when the person reaches the authorization
page. Platforms do not register: their client is created with the account.

Public for a public client. A confidential client needs an unrestricted key.




## OpenAPI

````yaml /api-reference/openapi.yaml post /oauth/register
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/register:
    post:
      tags:
        - OAuth
      summary: Register 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).


        Registers an OAuth client, as Dynamic Client Registration (RFC 7591)
        defines. MCP clients

        call it on their own the first time they connect, so a person needs only
        the server's URL.


        Sent without a key, it registers a public client:
        `token_endpoint_auth_method` must be

        `none`, and the grants are `authorization_code` and `refresh_token`. A
        public client acts

        for whoever signs in on the authorization page.


        Sent with your secret key, it registers a confidential client that
        belongs to your account

        and receives a `client_secret`, shown only in this response. Use one for
        an

        [RSL](/standard/interop/rsl) client that requests `License` tokens with

        `client_credentials`, or for a content host that checks them with

        [`POST /oauth/introspect`](/api-reference/oauth/introspect-a-token). A
        `License` token

        issued to it draws on your account's licenses.


        A client can also skip registration and use the HTTPS URL of a client
        metadata document as

        its `client_id`; Reflections reads the document when the person reaches
        the authorization

        page. Platforms do not register: their client is created with the
        account.


        Public for a public client. A confidential client needs an unrestricted
        key.
      operationId: createClient
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientCreate'
            examples:
              mcp_client:
                summary: A desktop agent registers itself
                value:
                  client_name: Fieldnote
                  client_uri: https://fieldnote.example
                  redirect_uris:
                    - http://127.0.0.1:33418/oauth/callback
                  grant_types:
                    - authorization_code
                    - refresh_token
                  response_types:
                    - code
                  token_endpoint_auth_method: none
                  scope: talent:read licenses:read checks:write generations:write
                  software_id: com.fieldnote.desktop
                  software_version: 4.2.0
              rsl_client:
                summary: A confidential client for RSL License tokens
                value:
                  client_name: Ridgeline asset pipeline
                  grant_types:
                    - client_credentials
                  token_endpoint_auth_method: client_secret_basic
      responses:
        '201':
          description: The registered client.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Client'
              examples:
                mcp_client:
                  summary: A public client
                  value:
                    client_id: cl_ra8t5tsberxpax0351jdyqgrb7
                    client_id_issued_at: 1792312320
                    client_name: Fieldnote
                    client_uri: https://fieldnote.example
                    redirect_uris:
                      - http://127.0.0.1:33418/oauth/callback
                    grant_types:
                      - authorization_code
                      - refresh_token
                    response_types:
                      - code
                    token_endpoint_auth_method: none
                    scope: talent:read licenses:read checks:write generations:write
                    software_id: com.fieldnote.desktop
                    software_version: 4.2.0
                    account: null
                rsl_client:
                  summary: A confidential client with its secret
                  value:
                    client_id: cl_zsyaax01q26b0kmq66g7wt70x9
                    client_id_issued_at: 1792312320
                    client_secret: rcs_ni2MbXp4oldIm8sItddmwS1_Aqt_VqkJMXmnjwc8hEQ
                    client_secret_expires_at: 0
                    client_name: Ridgeline asset pipeline
                    redirect_uris: []
                    grant_types:
                      - client_credentials
                    response_types: []
                    token_endpoint_auth_method: client_secret_basic
                    account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        '400':
          description: >
            The metadata is not acceptable. `error` is `invalid_redirect_uri` (a
            redirect URI that

            is not HTTPS or a loopback address) or `invalid_client_metadata`
            (any other field,

            including a confidential client registered without a secret key).
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthError'
              example:
                error: invalid_redirect_uri
                error_description: >-
                  http://fieldnote.example/callback is not HTTPS or a loopback
                  address.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
        '503':
          $ref: '#/components/responses/Unavailable'
      security:
        - {}
        - SecretKey: []
      servers:
        - url: https://app.reflections.ai
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >
            curl --fail-with-body --max-time 30 -X POST
            'https://app.reflections.ai/oauth/register' \
              -H "Content-Type: application/json" \
              --data-raw '{
              "client_name": "Fieldnote",
              "client_uri": "https://fieldnote.example",
              "redirect_uris": [
                "http://127.0.0.1:33418/oauth/callback"
              ],
              "grant_types": [
                "authorization_code",
                "refresh_token"
              ],
              "response_types": [
                "code"
              ],
              "token_endpoint_auth_method": "none",
              "scope": "talent:read licenses:read checks:write generations:write",
              "software_id": "com.fieldnote.desktop",
              "software_version": "4.2.0"
            }'
        - lang: typescript
          label: TypeScript
          source: >
            import { exit } from "node:process";


            const response = await
            fetch("https://app.reflections.ai/oauth/register", {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "client_name": "Fieldnote",
                "client_uri": "https://fieldnote.example",
                "redirect_uris": [
                  "http://127.0.0.1:33418/oauth/callback"
                ],
                "grant_types": [
                  "authorization_code",
                  "refresh_token"
                ],
                "response_types": [
                  "code"
                ],
                "token_endpoint_auth_method": "none",
                "scope": "talent:read licenses:read checks:write generations:write",
                "software_id": "com.fieldnote.desktop",
                "software_version": "4.2.0"
              }),
              signal: AbortSignal.timeout(30_000),
            });

            const responseBody = await response.text();

            if (!response.ok) {
              console.error(`HTTP ${response.status}: ${responseBody}`);
              exit(1);
            }

            console.log(responseBody);
        - lang: python
          label: Python
          source: |
            import json
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            headers = {
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "client_name": "Fieldnote",
                "client_uri": "https://fieldnote.example",
                "redirect_uris": ["http://127.0.0.1:33418/oauth/callback"],
                "grant_types": ["authorization_code", "refresh_token"],
                "response_types": ["code"],
                "token_endpoint_auth_method": "none",
                "scope": "talent:read licenses:read checks:write generations:write",
                "software_id": "com.fieldnote.desktop",
                "software_version": "4.2.0",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/oauth/register",
                              method="POST", headers=headers, data=data)
            try:
                with urlopen(request, timeout=30) as response:
                    print(response.read().decode("utf-8"))
            except HTTPError as error:
                error_body = error.read().decode("utf-8")
                raise RuntimeError(f"HTTP {error.code}: {error_body}") from error
        - lang: go
          label: Go
          source: |
            package main

            import (
                "fmt"
                "io"
                "net/http"
                "strings"
                "time"
            )

            func main() {
                body := strings.NewReader(`{
                  "client_name": "Fieldnote",
                  "client_uri": "https://fieldnote.example",
                  "redirect_uris": [
                    "http://127.0.0.1:33418/oauth/callback"
                  ],
                  "grant_types": [
                    "authorization_code",
                    "refresh_token"
                  ],
                  "response_types": [
                    "code"
                  ],
                  "token_endpoint_auth_method": "none",
                  "scope": "talent:read licenses:read checks:write generations:write",
                  "software_id": "com.fieldnote.desktop",
                  "software_version": "4.2.0"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/register", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Content-Type", "application/json")
                client := &http.Client{Timeout: 30 * time.Second}
                response, err := client.Do(request)
                if err != nil {
                    panic(err)
                }
                defer response.Body.Close()
                responseBody, err := io.ReadAll(response.Body)
                if err != nil {
                    panic(err)
                }
                if response.StatusCode < 200 || response.StatusCode >= 300 {
                    panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, responseBody))
                }
                fmt.Print(string(responseBody))
            }
components:
  schemas:
    ClientCreate:
      type: object
      description: Client metadata, as RFC 7591 defines it.
      required:
        - client_name
      properties:
        client_name:
          type: string
          maxLength: 80
          description: Shown to the person on the authorization page.
        client_uri:
          type: string
          format: uri
          description: The client's home page, linked on the authorization page.
        logo_uri:
          type: string
          format: uri
          description: A square logo shown on the authorization page, PNG or SVG.
        redirect_uris:
          type: array
          items:
            type: string
            format: uri
          description: >
            Where the authorization page may send the person back. Each is an
            HTTPS URL, or an

            `http://127.0.0.1` or `http://[::1]` loopback URL for a native app,
            which may use any

            port (RFC 8252). Required when `grant_types` includes
            `authorization_code`.
        grant_types:
          type: array
          items:
            type: string
            enum:
              - authorization_code
              - refresh_token
              - client_credentials
          default:
            - authorization_code
            - refresh_token
          description: >-
            The grants the client will use. `client_credentials` needs a secret
            key on the request.
        response_types:
          type: array
          items:
            type: string
            enum:
              - code
          description: >
            Defaults to `["code"]` when `grant_types` includes
            `authorization_code`, and to `[]`

            otherwise.
        token_endpoint_auth_method:
          type: string
          enum:
            - none
            - client_secret_basic
            - client_secret_post
          default: none
          description: >
            `none` for a public client, such as a desktop or command-line agent.

            `client_secret_basic` or `client_secret_post` for a confidential
            client, which needs a

            secret key on the request.
        scope:
          type: string
          description: >-
            Space-separated scopes the client may ask for. Defaults to every MCP
            scope.
        software_id:
          type: string
          description: >-
            Identifies the client software across its installations, such as a
            reverse domain name.
        software_version:
          type: string
          description: The version of the client software.
    Client:
      type: object
      description: A registered OAuth client, as RFC 7591 returns it.
      required:
        - client_id
        - client_id_issued_at
        - client_name
        - redirect_uris
        - grant_types
        - response_types
        - token_endpoint_auth_method
        - account
      properties:
        client_id:
          type: string
          pattern: ^cl_[0-9a-hjkmnp-tv-z]{26}$
          description: Unique identifier for the client, `cl_…`.
        client_id_issued_at:
          type: integer
          description: Unix seconds when the client was registered.
        client_secret:
          type: string
          description: >
            A confidential client's secret, `rcs_…`. Shown only in this
            response: store it with your

            other secrets.
        client_secret_expires_at:
          type: integer
          description: '`0`: the secret does not expire.'
        client_name:
          type: string
          description: The registered name.
        client_uri:
          type: string
          format: uri
          description: The registered home page.
        logo_uri:
          type: string
          format: uri
          description: The registered logo.
        redirect_uris:
          type: array
          items:
            type: string
            format: uri
          description: The registered redirect URIs.
        grant_types:
          type: array
          items:
            type: string
            enum:
              - authorization_code
              - refresh_token
              - client_credentials
          description: The grants the client may use.
        response_types:
          type: array
          items:
            type: string
            enum:
              - code
          description: The response types the client may use.
        token_endpoint_auth_method:
          type: string
          enum:
            - none
            - client_secret_basic
            - client_secret_post
          description: How the client authenticates at the token endpoint.
        scope:
          type: string
          description: The scopes the client may ask for.
        software_id:
          type: string
          description: The registered software ID.
        software_version:
          type: string
          description: The registered software version.
        account:
          type:
            - string
            - 'null'
          pattern: ^acct_[0-9a-hjkmnp-tv-z]{26}$
          description: >
            The account that registered a confidential client, whose licenses
            its `License` tokens

            draw on. `null` for a public client.
    OAuthError:
      type: object
      description: >
        An OAuth error, as RFC 6749 §5.2 and RFC 7591 §3.2.2 define it. The
        OAuth endpoints return

        it for `400` and `401`.
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - invalid_request
            - invalid_client
            - invalid_grant
            - unauthorized_client
            - unsupported_grant_type
            - invalid_scope
            - invalid_target
            - invalid_redirect_uri
            - invalid_client_metadata
          description: The error code. Each endpoint lists the codes it returns.
        error_description:
          type: string
          description: >-
            A sentence for the developer. Do not show it to the person signing
            in.
    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
  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
  responses:
    Unauthorized:
      description: The key is missing, unknown or revoked.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.reflections.ai/errors/invalid_api_key
            title: The API key is not valid
            status: 401
            code: invalid_api_key
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    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'
  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.