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:
  /account:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveAccount
      summary: Retrieve your account
      x-mint:
        href: /api-reference/account/retrieve-your-account
      description: |
        **Test mode available. Live mode available for this read.** Test keys return sandbox account data; live keys return the authenticated account. See [Modes](/api-reference/introduction#test-and-live-mode) for the supported operations.

        Returns the account that owns the calling key.

        Works with any key, restricted or not.
      tags: [Account]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
      responses:
        "200":
          description: The account.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Account" }
              examples:
                account: { $ref: "#/components/examples/Account" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/account' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/account", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/account",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/account", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /talent:
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: listTalent
      summary: List talent
      x-mint:
        href: /api-reference/talent/list-talent
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Lists talent visible to the caller: every talent who opted into protection, plus the
        listing details of talent who accept license requests. Use `licensed=true` to list only
        talent the caller (or the account in `Reflections-Account`) holds an active license for.

        Restricted keys need `talent:read`.
      tags: [Talent]
      security:
        - { SecretKey: [talent:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: q
          in: query
          description: Search names and aliases.
          schema: { type: string, maxLength: 200 }
        - name: facet_type
          in: query
          description: Only talent with a ready facet of this type.
          schema: { $ref: "#/components/schemas/FacetType" }
        - name: licensed
          in: query
          description: Only talent with an active license held by the licensee.
          schema: { type: boolean }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of talent.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/TalentList" }
              examples:
                licensed_voice:
                  summary: Talent named Maya with a licensed voice
                  value:
                    object: list
                    data:
                      - id: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        object: talent
                        livemode: true
                        name: Maya Okafor
                        aliases:
                          - Maya O.
                        status: active
                        verification:
                          verified: true
                          method: id_document
                          verified_at: "2026-06-11T09:30:00Z"
                        protection:
                          references: true
                          modalities:
                            - image
                            - video
                            - speech
                        posture:
                          default: license_required
                          accepts_requests: true
                          rules:
                            - purpose: political
                              declaration: prohibited
                            - kind: endorsement
                              purpose: advertising
                              declaration: license_required
                            - modality: text
                              kind: reference
                              declaration: allowed
                              obligations: []
                        representation:
                          - account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                            name: Summit Talent Management
                            role: manager
                            powers:
                              - issue_licenses
                              - review_outputs
                              - revoke
                              - receive_statements
                        facets:
                          - id: fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                            type: likeness
                            label: Studio likeness
                            status: ready
                          - id: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                            type: voice
                            label: Speaking voice
                            status: ready
                          - id: fct_q4r6s9t0wxyhk5zba2q8v1m3n7
                            type: name
                            label: Name
                            status: ready
                        hcs_subject_id: null
                        profile_url: https://app.reflections.ai/t/maya-okafor
                        created_at: "2026-06-11T09:00:00Z"
                        updated_at: "2026-10-01T12:00:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/talent?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/talent?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/talent?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/talent?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /talent/index:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveTalentIndex
      summary: Download the name index
      x-mint:
        href: /api-reference/talent/download-the-name-index
        metadata:
          playground: simple
      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).

        Returns the signed name index for matching talent locally: every protected talent's ID,
        names, aliases and transliterations. Refresh it at least hourly using `ETag`. A local match
        tells you to send a check; no local match does not mean a prompt is clear, because indirect
        references and reference media still need the server.

        Restricted keys need `talent:read`.
      tags: [Talent]
      security:
        - { SecretKey: [talent:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: If-None-Match
          in: header
          description: The `ETag` of the index you hold.
          schema: { type: string }
      responses:
        "200":
          description: The current index.
          headers:
            ETag:
              description: Version of this index.
              schema: { type: string }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/TalentIndex" }
              examples:
                index:
                  summary: The signed name index
                  value:
                    object: talent_index
                    version: "20261017.17"
                    generated_at: "2026-10-17T17:00:00Z"
                    expires_at: "2026-10-17T19:00:00Z"
                    normalization: nfkc_casefold
                    entries:
                      - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        names:
                          - maya okafor
                          - maya o.
                        common: false
                      - talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                        names:
                          - jonah reyes
                        common: false
                    signature: eyJhbGciOiJFUzI1NiIs…
        "304":
          description: Your index is current.
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/talent/index' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/talent/index", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/talent/index",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/talent/index", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /talent/{talent_id}:
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: retrieveTalent
      summary: Retrieve a talent
      x-mint:
        href: /api-reference/talent/retrieve-a-talent
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Returns a talent with their public posture, verification and facets.

        Restricted keys need `talent:read`.
      tags: [Talent]
      security:
        - { SecretKey: [talent:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/TalentId"
      responses:
        "200":
          description: The talent.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Talent" }
              examples:
                talent: { $ref: "#/components/examples/Talent" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /talent/{talent_id}/facets:
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: listTalentFacets
      summary: List a talent's facets
      x-mint:
        href: /api-reference/facets/list-talent-facets
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Lists a talent's facets, newest first. A talent can have several facets of one type, such as
        two voices; name the one you use in a check's `facet`. `provider_bindings` are shown only to
        the provider that holds the copy and to licensees whose license includes `material_access`
        for the facet.

        Restricted keys need `talent:read`.
      tags: [Facets]
      security:
        - { SecretKey: [talent:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/TalentId"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of facets.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/FacetList" }
              examples:
                facets:
                  summary: Maya Okafor's likeness, name and voice
                  value:
                    object: list
                    data:
                      - id: fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        object: facet
                        livemode: true
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        type: likeness
                        label: Studio likeness
                        status: ready
                        modalities:
                          - image
                          - video
                        material:
                          items: 18
                          updated_at: "2026-09-24T15:30:00Z"
                        provider_bindings: []
                        created_at: "2026-09-03T10:15:00Z"
                        updated_at: "2026-09-24T15:30:00Z"
                      - id: fct_q4r6s9t0wxyhk5zba2q8v1m3n7
                        object: facet
                        livemode: true
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        type: name
                        label: Name
                        status: ready
                        modalities:
                          - text
                        material: null
                        provider_bindings: []
                        created_at: "2026-09-03T10:12:00Z"
                        updated_at: "2026-09-03T10:12:00Z"
                      - id: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                        object: facet
                        livemode: true
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        type: voice
                        label: Speaking voice
                        status: ready
                        modalities:
                          - speech
                        material:
                          items: 12
                          updated_at: "2026-09-20T10:00:00Z"
                        provider_bindings:
                          - provider: example-voice-provider
                            kind: voice
                            external_id: vx_4f9a2c
                            status: active
                        created_at: "2026-06-12T09:00:00Z"
                        updated_at: "2026-09-20T10:00:00Z"
                    has_more: false
                    next_cursor: null
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s/facets?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s/facets?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s/facets?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/talent/tal_9t0wxyhk5zba2q8v1m3n7p4r6s/facets?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /facets/{facet_id}:
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: retrieveFacet
      summary: Retrieve a facet
      x-mint:
        href: /api-reference/facets/retrieve-a-facet
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Returns a facet: what it covers, the modalities it can generate, how much reference material
        it holds and which model providers hold copies. `provider_bindings` are shown only to that
        provider and to licensees whose license includes `material_access` for the facet.

        Restricted keys need `talent:read`.
      tags: [Facets]
      security:
        - { SecretKey: [talent:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/FacetId"
      responses:
        "200":
          description: The facet.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Facet" }
              examples:
                facet: { $ref: "#/components/examples/Facet" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /facets/{facet_id}/material:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveFacetMaterial
      summary: Retrieve licensed material
      x-mint:
        href: /api-reference/facets/retrieve-licensed-material
        metadata:
          playground: simple
      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).

        Returns short-lived download URLs for the reference material a license lets the licensee
        send to a model, such as the reference stills of a likeness. Each item carries its
        `sha256`; send exactly those bytes. Requires a license whose scope includes
        `material_access` for this facet. URLs expire after 5 minutes and every download is
        recorded on the talent's record.

        Restricted keys need `licenses:read`.
      tags: [Facets]
      security:
        - { SecretKey: [licenses:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/FacetId"
        - name: license
          in: query
          required: true
          description: The license that grants material access.
          example: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
          schema: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
      responses:
        "200":
          description: The material.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/FacetMaterial" }
              examples:
                voice_samples:
                  summary: Voice samples under a voice license
                  value:
                    object: facet_material
                    facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    expires_at: "2026-10-14T16:25:03Z"
                    items:
                      - id: mat_zffz7aewxkb1hpdma9m5w37zb8
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 4cebb1df0b0005098a1e13cbde6de657fb496d868f34b0ba550f0eb632770118
                        size: 4585004
                        duration_ms: 31840
                        url: https://files.reflections.ai/m/mat_zffz7aewxkb1hpdma9m5w37zb8?expires=1791995103&signature=3ce6286e18accc8b0f8c3db4eb17aee9fff44609612
                      - id: mat_fpzq0ggr5sg91sv7dzrptmrw1n
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: ecff26300951e866c0c7a6db07e7dcb0d92d0874305dcb5dd854e35947734078
                        size: 4091084
                        duration_ms: 28410
                        url: https://files.reflections.ai/m/mat_fpzq0ggr5sg91sv7dzrptmrw1n?expires=1791995103&signature=c0e46f6a18a2bac3f6bb7eae02f4d2679982ef0045f
                      - id: mat_38p2v2zpjm0sezg5be59w5nww2
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: d643198403c86054c97007384ac6c1ffe93558519c5d23d7721a27c5796da6cc
                        size: 6353324
                        duration_ms: 44120
                        url: https://files.reflections.ai/m/mat_38p2v2zpjm0sezg5be59w5nww2?expires=1791995103&signature=c34784730b7c58af5b8e5622929bbaac955611b6344
                      - id: mat_ath88yzbkn61qx00prngj4ymxy
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: f368b0a14013c48123544b4fe55b32b73174c560966e33acb01646ccb5fb7330
                        size: 2845484
                        duration_ms: 19760
                        url: https://files.reflections.ai/m/mat_ath88yzbkn61qx00prngj4ymxy?expires=1791995103&signature=935302111354709e8f27d08a12e86c755a8f7013e05
                      - id: mat_vhv37k68efgaqvab2qkyw6wzcj
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 5aff701e270e674472ae1dafee8dad826d612bbb509dc7122deddd9660defcc5
                        size: 5224364
                        duration_ms: 36280
                        url: https://files.reflections.ai/m/mat_vhv37k68efgaqvab2qkyw6wzcj?expires=1791995103&signature=2c2b08700888b6dc59d597a56f4a0db84fff6ed1a09
                      - id: mat_p07weqpc3gn7zas5p8wtnjynen
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 186036056134c4da77b51a4c5820e5918b762310bad0cca7913a9363cafb002c
                        size: 3733964
                        duration_ms: 25930
                        url: https://files.reflections.ai/m/mat_p07weqpc3gn7zas5p8wtnjynen?expires=1791995103&signature=70b3a88d8e6f01ced2c40eb3eaa5ae75469a754c287
                      - id: mat_wa5zww7pz1qqy32rpw1nrzyptb
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 6b60e779aabf89f0cdaeba96198506816cdf9eeb5c0935fe66aa4ceb6f78c1c6
                        size: 5813324
                        duration_ms: 40370
                        url: https://files.reflections.ai/m/mat_wa5zww7pz1qqy32rpw1nrzyptb?expires=1791995103&signature=b6537d459bf82b5aae3b5409341f472a2e10ca14a0c
                      - id: mat_dmk84vfvnvys94g12h9wrkc7yg
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 7e6371a08f501785586ab6bf9b397ac1f91f98bbe4da598074cb68ce54a13324
                        size: 3261644
                        duration_ms: 22650
                        url: https://files.reflections.ai/m/mat_dmk84vfvnvys94g12h9wrkc7yg?expires=1791995103&signature=c62d97161f66a74cc442606d139bea604b5ced6af71
                      - id: mat_g9s62txt5wajscqskyews8pk4k
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 3a47d9aa9bf8f504813867835a3bd4c556087bc18c23d093c1dad213c7d40264
                        size: 4825484
                        duration_ms: 33510
                        url: https://files.reflections.ai/m/mat_g9s62txt5wajscqskyews8pk4k?expires=1791995103&signature=095074067f83cf5ae5efebb1eab8366e539e351a94a
                      - id: mat_ns8wtd4qqq1adaz6vex49s9f27
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: e3039eef0d0a60a54a114ce50a9d3214b31ee75a4222c5977261b155b6dbcf7a
                        size: 4302764
                        duration_ms: 29880
                        url: https://files.reflections.ai/m/mat_ns8wtd4qqq1adaz6vex49s9f27?expires=1791995103&signature=286161c373b22354115329ed66686f605106c88ebb9
                      - id: mat_0axxrdtfj5p9f0rcchv6pq8f0m
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 8fc5abd51bea465771aa4f17eb04f1d7d287879f7ee41716c5fbf44f2393b348
                        size: 5474924
                        duration_ms: 38020
                        url: https://files.reflections.ai/m/mat_0axxrdtfj5p9f0rcchv6pq8f0m?expires=1791995103&signature=0acf7b5aed66e692bbf5e500c95911832371ebacca5
                      - id: mat_mxvpmjs64neggm8s4ytea3rkwz
                        kind: voice_sample
                        media_type: audio/wav
                        sha256: 359683c5c6d90e4ca0f820be6d0b390474314ab1fba3c31de52ab4da0ef26143
                        size: 3922604
                        duration_ms: 27240
                        url: https://files.reflections.ai/m/mat_mxvpmjs64neggm8s4ytea3rkwz?expires=1791995103&signature=a028b4303c8775e43def06193f67404232d4b002f4e
                    obligations:
                      - type: no_training
                        material: voice
                      - type: delete_material
                        material: voice
                        within: P30D
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8/material?license=lic_ba2q8v1m3n7p4r6s9t0wxyhk5z' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8/material?license=lic_ba2q8v1m3n7p4r6s9t0wxyhk5z", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8/material?license=lic_ba2q8v1m3n7p4r6s9t0wxyhk5z",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/facets/fct_v1m3n7p4r6s9t0wxyhk5zba2q8/material?license=lic_ba2q8v1m3n7p4r6s9t0wxyhk5z", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /resolutions:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createResolution
      summary: Resolve talent
      x-mint:
        href: /api-reference/resolutions/resolve-talent
        metadata:
          playground: simple
      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).

        Finds which talent a text, image or voice sample invokes, and classifies the use. Matching is
        inclusive: every candidate at `medium` confidence or higher is listed. A resolution never
        clears a use. `status: none` means no protected talent was found, not that the request is
        permitted. Checks resolve automatically, so call this only when you need candidates for
        your own interface, such as autocomplete or a "did you mean" prompt, or to classify how a
        message uses a person before you decide whether to check it.

        Restricted keys need `talent:read`.
      tags: [Resolutions]
      security:
        - { SecretKey: [talent:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/ResolutionCreate" }
            examples:
              name:
                summary: A name in a prompt
                value:
                  inputs:
                    - role: prompt
                      text: "A podcast intro read by Maya Okafor"
                  modality: speech
      responses:
        "200":
          description: The resolution.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Resolution" }
              examples:
                resolution: { $ref: "#/components/examples/Resolution" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/resolutions' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "inputs": [
                {
                  "role": "prompt",
                  "text": "A podcast intro read by Maya Okafor"
                }
              ],
              "modality": "speech"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/resolutions", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "inputs": [
                  {
                    "role": "prompt",
                    "text": "A podcast intro read by Maya Okafor"
                  }
                ],
                "modality": "speech"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "inputs": [{"role": "prompt", "text": "A podcast intro read by Maya Okafor"}],
                "modality": "speech",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/resolutions",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_RESOLUTION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "inputs": [
                    {
                      "role": "prompt",
                      "text": "A podcast intro read by Maya Okafor"
                    }
                  ],
                  "modality": "speech"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/resolutions", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /licenses:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: listLicenses
      summary: List licenses
      x-mint:
        href: /api-reference/licenses/list-licenses
      description: |
        **Test mode available. Live mode available for this read.** Test keys return fictional fixtures. A live key reads only licenses whose sole licensee is the calling account. Delegated connections and representative access are planned.

        Live results include the current signed revision's `terms_digest` and a partial `scope`:
        `window`, `required_attributes`, `release_policy` and `final_deliverables`, plus
        `external_creation` only when that grant is explicitly signed. Omitted fields
        grant nothing. Signed channel and territory labels are not mapped to protocol enums. No private
        reference IDs or source media are returned, and live revision retrieval is not available.
        See [Live license reads](/concepts/licenses#live-license-reads).

        Restricted keys need `licenses:read`.
      tags: [Licenses]
      security:
        - { SecretKey: [licenses:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: talent
          in: query
          description: Only licenses granted by this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: Only licenses with this status, such as `active`. Live reads also accept `void`; the sandbox status filter does not.
          schema: { $ref: "#/components/schemas/LicenseStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of licenses.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseList" }
              examples:
                talent_licenses:
                  summary: One talent's active licenses, seen by her manager
                  value:
                    object: list
                    data:
                      - id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        object: license
                        livemode: true
                        status: active
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        issued_by:
                          party: talent
                          account: null
                        handle: K7Q4M2
                        current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        revision_number: 1
                        pending_revision: null
                        terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                        scope:
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          window:
                            starts_at: "2026-10-01T00:00:00-04:00"
                            ends_at: "2027-03-31T00:00:00-04:00"
                            time_zone: America/New_York
                          adjustments:
                            reframe: true
                            background_extension: true
                            lighting: true
                            text_overlay: true
                            body_and_age: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skin_retouch: false
                            endorsement: false
                          prohibited_changes:
                            - body_and_age
                            - expression
                            - hair
                            - pose
                            - skin_retouch
                            - endorsement
                          required_attributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          rules:
                            never:
                              - Do not show alcohol or tobacco.
                            always: []
                            brief: null
                          release_policy: per_output_review
                          escalation_window: P7D
                          final_deliverables: 24
                          sessions:
                            permitted: false
                          material_access: []
                          platforms:
                            mode: any_connected
                            accounts: []
                          sublicense: none
                          training: prohibited
                          disclosure: brand
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity:
                            exclusive: false
                            category: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: placements
                              rate:
                                amount: 25000
                                currency: usd
                              per: 1
                            minimum:
                              amount: 500000
                              currency: usd
                            schedule: monthly
                        acceptance_url: null
                        accepted_at: "2026-09-28T16:02:00Z"
                        suspended_at: null
                        revoked_at: null
                        declined_at: null
                        metadata: {}
                        created_at: "2026-09-27T11:15:00Z"
                      - id: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        object: license
                        livemode: true
                        status: active
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        issued_by:
                          party: talent
                          account: null
                        handle: V6R2T9
                        current_revision: lrv_7p4r6s9t0wxyhk5zba2q8v1m3n
                        revision_number: 1
                        pending_revision: null
                        scope:
                          facets:
                            - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                          modalities:
                            - speech
                          kinds:
                            - impersonation
                          purposes:
                            - personal
                            - branded_content
                          commercial: true
                          channels:
                            - in_app
                            - audio
                            - web
                          territories:
                            - US
                          window:
                            starts_at: "2026-09-02T00:00:00Z"
                            ends_at: "2027-06-30T23:59:59Z"
                            time_zone: null
                          required_attributes:
                            - identity.samePerson
                          release_policy: after_checks
                          escalation_window: P7D
                          final_deliverables: null
                          monthly_limits:
                            seconds: 100000
                          sessions:
                            permitted: true
                            sampling:
                              audio_window_max: PT15S
                              transcript: every_turn
                          material_access: []
                          platforms:
                            mode: listed
                            accounts:
                              - acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                          sublicense: end_users_personal
                          training: prohibited
                          disclosure: licensed
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: seconds
                              rate:
                                amount: 2
                                currency: usd
                              per: 1
                            schedule: monthly
                        acceptance_url: null
                        accepted_at: "2026-09-01T16:45:00Z"
                        suspended_at: null
                        revoked_at: null
                        declined_at: null
                        metadata: {}
                        created_at: "2026-09-01T10:00:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/licenses?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/licenses?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/licenses?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/licenses?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /licenses/{license_id}:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveLicense
      summary: Retrieve a license
      x-mint:
        href: /api-reference/licenses/retrieve-a-license
      description: |
        **Test mode available. Live mode available for this read.** Test keys return fictional fixtures. A live key reads only a license whose sole licensee is the calling account. Another account's license returns `404 resource_not_found`.

        Returns `status`, the current signed revision's identity and digest, and a partial live
        `scope`: `window`, `required_attributes`, `release_policy` and `final_deliverables`, plus
        `external_creation` only when explicitly signed.
        Omitted fields grant nothing. No private reference IDs or source media are returned.
        Delegated access and live [revision retrieval](/api-reference/licenses/retrieve-a-license-revision)
        remain planned. See [Live license reads](/concepts/licenses#live-license-reads).

        Restricted keys need `licenses:read`.
      tags: [Licenses]
      security:
        - { SecretKey: [licenses:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseId"
      responses:
        "200":
          description: The license.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/License" }
              examples:
                license: { $ref: "#/components/examples/License" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /licenses/{license_id}/suspend:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: suspendLicense
      summary: Suspend a license
      x-mint:
        href: /api-reference/licenses/suspend-a-license
        metadata:
          playground: simple
      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).

        Pauses a license, such as during a dispute. Needs a mandate with `revoke` for the talent.
        Until you resume it, checks deny with `license_suspended`, open sessions under it end, and
        renewals fail. Held outputs stay held and released outputs are unaffected. The licensee
        and connected platforms receive `license.suspended`. A suspension is not a revocation: it
        can be undone, and it asks nothing of platforms beyond dropping cached decisions.

        Restricted keys need `licenses:write`.
      tags: [Licenses]
      security:
        - { SecretKey: [licenses:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/LicenseId"
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseStatusChange" }
            examples:
              review:
                summary: Pause the license during a review
                value:
                  note: Paused while we review two October placements with Ridgeline.
      responses:
        "200":
          description: The suspended license.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/License" }
              examples:
                suspended:
                  summary: The suspended license
                  value:
                    id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                    object: license
                    livemode: true
                    status: suspended
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    issued_by:
                      party: talent
                      account: null
                    handle: K7Q4M2
                    current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                    revision_number: 1
                    pending_revision: null
                    terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                      modalities:
                        - image
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                        - CA
                      window:
                        starts_at: "2026-10-01T00:00:00-04:00"
                        ends_at: "2027-03-31T00:00:00-04:00"
                        time_zone: America/New_York
                      adjustments:
                        reframe: true
                        background_extension: true
                        lighting: true
                        text_overlay: true
                        body_and_age: false
                        expression: false
                        hair: false
                        pose: false
                        wardrobe: true
                        objects: true
                        skin_retouch: false
                        endorsement: false
                      prohibited_changes:
                        - body_and_age
                        - expression
                        - hair
                        - pose
                        - skin_retouch
                        - endorsement
                      required_attributes:
                        - identity.samePerson
                        - appearance.bodyAndAge
                        - appearance.expression
                        - appearance.hair
                        - appearance.pose
                        - appearance.skinRetouch
                        - context.endorsement
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: per_output_review
                      escalation_window: P7D
                      final_deliverables: 24
                      sessions:
                        permitted: false
                      material_access: []
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: brand
                      attribution: null
                      post_revocation:
                        policy: retain
                      exclusivity:
                        exclusive: false
                        category: null
                      conflicts: []
                      compensation:
                        type: per_unit
                        per_unit:
                          units: placements
                          rate:
                            amount: 25000
                            currency: usd
                          per: 1
                        minimum:
                          amount: 500000
                          currency: usd
                        schedule: monthly
                    acceptance_url: null
                    accepted_at: "2026-09-28T16:02:00Z"
                    suspended_at: "2026-10-08T15:40:00Z"
                    revoked_at: null
                    declined_at: null
                    metadata: {}
                    created_at: "2026-09-27T11:15:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY:?Set REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/suspend' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "note": "Paused while we review two October placements with Ridgeline."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/suspend", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "note": "Paused while we review two October placements with Ridgeline."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"note": "Paused while we review two October placements with Ridgeline."}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/suspend",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_SUSPEND_LICENSE_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "note": "Paused while we review two October placements with Ridgeline."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/suspend", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /licenses/{license_id}/resume:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: resumeLicense
      summary: Resume a license
      x-mint:
        href: /api-reference/licenses/resume-a-license
        metadata:
          playground: simple
      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).

        Ends a suspension. Needs a mandate with `revoke` for the talent. Checks may allow uses
        under the license again, and the licensee and connected platforms receive
        `license.resumed`. Sessions that ended stay ended.

        Restricted keys need `licenses:write`.
      tags: [Licenses]
      security:
        - { SecretKey: [licenses:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/LicenseId"
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseStatusChange" }
            examples:
              review_complete:
                summary: Resume after the review
                value:
                  note: Review complete. Placements may continue.
      responses:
        "200":
          description: The active license.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/License" }
              examples:
                active:
                  summary: The license, active again
                  value:
                    id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                    object: license
                    livemode: true
                    status: active
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    issued_by:
                      party: talent
                      account: null
                    handle: K7Q4M2
                    current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                    revision_number: 1
                    pending_revision: null
                    terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                      modalities:
                        - image
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                        - CA
                      window:
                        starts_at: "2026-10-01T00:00:00-04:00"
                        ends_at: "2027-03-31T00:00:00-04:00"
                        time_zone: America/New_York
                      adjustments:
                        reframe: true
                        background_extension: true
                        lighting: true
                        text_overlay: true
                        body_and_age: false
                        expression: false
                        hair: false
                        pose: false
                        wardrobe: true
                        objects: true
                        skin_retouch: false
                        endorsement: false
                      prohibited_changes:
                        - body_and_age
                        - expression
                        - hair
                        - pose
                        - skin_retouch
                        - endorsement
                      required_attributes:
                        - identity.samePerson
                        - appearance.bodyAndAge
                        - appearance.expression
                        - appearance.hair
                        - appearance.pose
                        - appearance.skinRetouch
                        - context.endorsement
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: per_output_review
                      escalation_window: P7D
                      final_deliverables: 24
                      sessions:
                        permitted: false
                      material_access: []
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: brand
                      attribution: null
                      post_revocation:
                        policy: retain
                      exclusivity:
                        exclusive: false
                        category: null
                      conflicts: []
                      compensation:
                        type: per_unit
                        per_unit:
                          units: placements
                          rate:
                            amount: 25000
                            currency: usd
                          per: 1
                        minimum:
                          amount: 500000
                          currency: usd
                        schedule: monthly
                    acceptance_url: null
                    accepted_at: "2026-09-28T16:02:00Z"
                    suspended_at: null
                    revoked_at: null
                    declined_at: null
                    metadata: {}
                    created_at: "2026-09-27T11:15:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY:?Set REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/resume' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "note": "Review complete. Placements may continue."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/resume", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "note": "Review complete. Placements may continue."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"note": "Review complete. Placements may continue."}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/resume",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_RESUME_LICENSE_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "note": "Review complete. Placements may continue."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/resume", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /licenses/{license_id}/revisions:
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: listLicenseRevisions
      summary: List license revisions
      x-mint:
        href: /api-reference/licenses/list-license-revisions
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Lists every signed revision of a license, newest first, including a pending or declined
        one; `status` tells them apart. A revision's terms never change.

        Restricted keys need `licenses:read`.
      tags: [Licenses]
      security:
        - { SecretKey: [licenses:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseId"
        - name: status
          in: query
          description: Only revisions with this status, such as `pending_acceptance`.
          schema: { $ref: "#/components/schemas/LicenseRevisionStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of revisions.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRevisionList" }
              examples:
                revisions:
                  summary: A current, a declined and a superseded revision
                  value:
                    object: list
                    data:
                      - id: lrv_5ecwa673wbbej5a0zkz2vxnk49
                        object: license_revision
                        livemode: true
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        number: 3
                        status: current
                        source_kind: change_request
                        terms:
                          releasePolicy: perOutputTalentReview
                          adjustments:
                            reframe: true
                            backgroundExtension: true
                            lighting: true
                            textOverlay: true
                            bodyAndAge: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skinRetouch: false
                            endorsement: false
                          channels:
                            - social
                            - web
                            - tv
                          territories:
                            - US
                            - CA
                          startsAt: "2026-10-01T00:00:00-04:00"
                          endsAt: "2027-03-31T00:00:00-04:00"
                          windowTimeZone: America/New_York
                          requiredAttributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          prohibitedChanges:
                            - bodyAndAge
                            - expression
                            - hair
                            - pose
                            - skinRetouch
                            - endorsement
                          neverExtras:
                            - Do not show alcohol or tobacco.
                          finalDeliverables: 24
                          isExclusive: false
                        terms_digest: sha256:5ddb67c82d7c5ed7217a95a48a6659c94d5a12eb6a740fa88d8323872f40d3cf
                        canonicalization: tlp-json-1
                        scope:
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                            - tv
                          territories:
                            - US
                            - CA
                          window:
                            starts_at: "2026-10-01T00:00:00-04:00"
                            ends_at: "2027-03-31T00:00:00-04:00"
                            time_zone: America/New_York
                          adjustments:
                            reframe: true
                            background_extension: true
                            lighting: true
                            text_overlay: true
                            body_and_age: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skin_retouch: false
                            endorsement: false
                          prohibited_changes:
                            - body_and_age
                            - expression
                            - hair
                            - pose
                            - skin_retouch
                            - endorsement
                          required_attributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          rules:
                            never:
                              - Do not show alcohol or tobacco.
                            always: []
                            brief: null
                          release_policy: per_output_review
                          escalation_window: P7D
                          final_deliverables: 24
                          sessions:
                            permitted: false
                          material_access: []
                          platforms:
                            mode: any_connected
                            accounts: []
                          sublicense: none
                          training: prohibited
                          disclosure: brand
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity:
                            exclusive: false
                            category: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: placements
                              rate:
                                amount: 25000
                                currency: usd
                              per: 1
                            minimum:
                              amount: 500000
                              currency: usd
                            schedule: monthly
                        enforcement:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.channels
                            enforcement: checked
                            stage:
                              - check
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            enforcement: checked
                            stage:
                              - generation
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            enforcement: checked
                            stage:
                              - check
                              - generation
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.isExclusive
                            enforcement: recorded
                            stage: []
                        signatures:
                          - party: talent
                            account: null
                            name: Maya Okafor
                            method: passkey
                            signed_at: "2026-10-20T15:30:00Z"
                          - party: licensee
                            account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                            name: Ridgeline
                            method: passkey
                            signed_at: "2026-10-21T13:05:00Z"
                        document_url: https://app.reflections.ai/l/K7Q4M2/revisions/3
                        created_at: "2026-10-20T15:30:00Z"
                      - id: lrv_p89j65tg7m6zby4b3pt3rd6dmh
                        object: license_revision
                        livemode: true
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        number: 2
                        status: declined
                        source_kind: amend
                        terms:
                          releasePolicy: perOutputTalentReview
                          adjustments:
                            reframe: true
                            backgroundExtension: true
                            lighting: true
                            textOverlay: true
                            bodyAndAge: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skinRetouch: false
                            endorsement: false
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          startsAt: "2026-10-01T00:00:00-04:00"
                          endsAt: "2027-03-31T00:00:00-04:00"
                          windowTimeZone: America/New_York
                          requiredAttributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          prohibitedChanges:
                            - bodyAndAge
                            - expression
                            - hair
                            - pose
                            - skinRetouch
                            - endorsement
                          neverExtras:
                            - Do not show alcohol or tobacco.
                            - Do not show her running on roads or near traffic.
                          finalDeliverables: 24
                          isExclusive: false
                        terms_digest: sha256:be28cb06d4af05a49be01483327a363afbd352a032d265a37283855f7bd8710a
                        canonicalization: tlp-json-1
                        scope:
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          window:
                            starts_at: "2026-10-01T00:00:00-04:00"
                            ends_at: "2027-03-31T00:00:00-04:00"
                            time_zone: America/New_York
                          adjustments:
                            reframe: true
                            background_extension: true
                            lighting: true
                            text_overlay: true
                            body_and_age: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skin_retouch: false
                            endorsement: false
                          prohibited_changes:
                            - body_and_age
                            - expression
                            - hair
                            - pose
                            - skin_retouch
                            - endorsement
                          required_attributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          rules:
                            never:
                              - Do not show alcohol or tobacco.
                              - Do not show her running on roads or near traffic.
                            always: []
                            brief: null
                          release_policy: per_output_review
                          escalation_window: P7D
                          final_deliverables: 24
                          sessions:
                            permitted: false
                          material_access: []
                          platforms:
                            mode: any_connected
                            accounts: []
                          sublicense: none
                          training: prohibited
                          disclosure: brand
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity:
                            exclusive: false
                            category: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: placements
                              rate:
                                amount: 25000
                                currency: usd
                              per: 1
                            minimum:
                              amount: 500000
                              currency: usd
                            schedule: monthly
                        enforcement:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.channels
                            enforcement: checked
                            stage:
                              - check
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            enforcement: checked
                            stage:
                              - generation
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            enforcement: checked
                            stage:
                              - check
                              - generation
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.isExclusive
                            enforcement: recorded
                            stage: []
                        signatures:
                          - party: representative
                            account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                            name: Lena Brooks
                            method: passkey
                            signed_at: "2026-10-18T10:20:00Z"
                        document_url: https://app.reflections.ai/l/K7Q4M2/revisions/2
                        created_at: "2026-10-18T10:20:00Z"
                      - id: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        object: license_revision
                        livemode: true
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        number: 1
                        status: superseded
                        source_kind: issue
                        terms:
                          releasePolicy: perOutputTalentReview
                          adjustments:
                            reframe: true
                            backgroundExtension: true
                            lighting: true
                            textOverlay: true
                            bodyAndAge: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skinRetouch: false
                            endorsement: false
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          startsAt: "2026-10-01T00:00:00-04:00"
                          endsAt: "2027-03-31T00:00:00-04:00"
                          windowTimeZone: America/New_York
                          requiredAttributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          prohibitedChanges:
                            - bodyAndAge
                            - expression
                            - hair
                            - pose
                            - skinRetouch
                            - endorsement
                          neverExtras:
                            - Do not show alcohol or tobacco.
                          finalDeliverables: 24
                          isExclusive: false
                        terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                        canonicalization: tlp-json-1
                        scope:
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          window:
                            starts_at: "2026-10-01T00:00:00-04:00"
                            ends_at: "2027-03-31T00:00:00-04:00"
                            time_zone: America/New_York
                          adjustments:
                            reframe: true
                            background_extension: true
                            lighting: true
                            text_overlay: true
                            body_and_age: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skin_retouch: false
                            endorsement: false
                          prohibited_changes:
                            - body_and_age
                            - expression
                            - hair
                            - pose
                            - skin_retouch
                            - endorsement
                          required_attributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          rules:
                            never:
                              - Do not show alcohol or tobacco.
                            always: []
                            brief: null
                          release_policy: per_output_review
                          escalation_window: P7D
                          final_deliverables: 24
                          sessions:
                            permitted: false
                          material_access: []
                          platforms:
                            mode: any_connected
                            accounts: []
                          sublicense: none
                          training: prohibited
                          disclosure: brand
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity:
                            exclusive: false
                            category: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: placements
                              rate:
                                amount: 25000
                                currency: usd
                              per: 1
                            minimum:
                              amount: 500000
                              currency: usd
                            schedule: monthly
                        enforcement:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.channels
                            enforcement: checked
                            stage:
                              - check
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            enforcement: checked
                            stage:
                              - generation
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            enforcement: checked
                            stage:
                              - check
                              - generation
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.isExclusive
                            enforcement: recorded
                            stage: []
                        signatures:
                          - party: talent
                            account: null
                            name: Maya Okafor
                            method: passkey
                            signed_at: "2026-09-27T11:15:00Z"
                          - party: licensee
                            account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                            name: Ridgeline
                            method: passkey
                            signed_at: "2026-09-28T16:02:00Z"
                        document_url: https://app.reflections.ai/l/K7Q4M2/revisions/1
                        created_at: "2026-09-27T11:15:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /licenses/{license_id}/revisions/{revision_id}:
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: retrieveLicenseRevision
      summary: Retrieve a license revision
      x-mint:
        href: /api-reference/licenses/retrieve-a-license-revision
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Returns one signed revision: the terms exactly as signed, their `terms_digest`, and a
        normalized `scope`. Compute the digest yourself to confirm you hold the signed document.

        Restricted keys need `licenses:read`.
      tags: [Licenses]
      security:
        - { SecretKey: [licenses:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseId"
        - name: revision_id
          in: path
          required: true
          description: |
            The revision's ID, such as the license's `current_revision` or `pending_revision`.
          example: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
          schema: { type: string, pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$" }
      responses:
        "200":
          description: The revision.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRevision" }
              examples:
                license_revision: { $ref: "#/components/examples/LicenseRevision" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions/lrv_p4r6s9t0wxyhk5zba2q8v1m3n7' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions/lrv_p4r6s9t0wxyhk5zba2q8v1m3n7", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions/lrv_p4r6s9t0wxyhk5zba2q8v1m3n7",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revisions/lrv_p4r6s9t0wxyhk5zba2q8v1m3n7", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /license_requests:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createLicenseRequest
      summary: Request a license
      x-mint:
        href: /api-reference/license-requests/request-a-license
        metadata:
          playground: simple
      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).

        Asks a talent for a new license, or for a wider one (`kind: change`). The talent or their
        representative answers in the Talent Portal or through the API: they may change any term,
        and only a person's signature makes a license. A request grants nothing. When it is
        signed, the licensee receives `license.issued` and accepts the license in the hosted
        acceptance page. No endpoint signs or accepts a license.

        Restricted keys need `license_requests:write`.
      tags: [License requests]
      security:
        - { SecretKey: [license_requests:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseRequestCreate" }
            examples:
              add_channel:
                summary: Ask to add TV after a denied check
                value:
                  kind: change
                  talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                  license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                  check: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
                  requested_scope:
                    channels:
                      - social
                      - web
                      - tv
                    final_deliverables: 30
                  offer:
                    type: flat
                    flat:
                      amount: 1000000
                      currency: usd
                    schedule: on_acceptance
                  note: We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.
                  metadata:
                    campaign: trail-winter-tv
      responses:
        "200":
          description: The license request.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRequest" }
              examples:
                sent:
                  summary: A change request waiting for the talent
                  value:
                    id: lrq_py3xqfvbjjcdhvf33y6c2w26jm
                    object: license_request
                    livemode: true
                    kind: change
                    status: sent
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                    license_revision: null
                    check: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
                    requested_scope:
                      channels:
                        - social
                        - web
                        - tv
                      final_deliverables: 30
                    offer:
                      type: flat
                      flat:
                        amount: 1000000
                        currency: usd
                      schedule: on_acceptance
                    note: We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.
                    decision_note: null
                    signed_at: null
                    declined_at: null
                    withdrawn_at: null
                    metadata:
                      campaign: trail-winter-tv
                    created_at: "2026-10-17T18:10:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/license_requests' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "kind": "change",
              "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
              "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
              "check": "chk_8v1m3n7p4r6s9t0wxyhk5zba2q",
              "requested_scope": {
                "channels": [
                  "social",
                  "web",
                  "tv"
                ],
                "final_deliverables": 30
              },
              "offer": {
                "type": "flat",
                "flat": {
                  "amount": 1000000,
                  "currency": "usd"
                },
                "schedule": "on_acceptance"
              },
              "note": "We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.",
              "metadata": {
                "campaign": "trail-winter-tv"
              }
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_requests", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "kind": "change",
                "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                "check": "chk_8v1m3n7p4r6s9t0wxyhk5zba2q",
                "requested_scope": {
                  "channels": [
                    "social",
                    "web",
                    "tv"
                  ],
                  "final_deliverables": 30
                },
                "offer": {
                  "type": "flat",
                  "flat": {
                    "amount": 1000000,
                    "currency": "usd"
                  },
                  "schedule": "on_acceptance"
                },
                "note": "We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.",
                "metadata": {
                  "campaign": "trail-winter-tv"
                }
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "kind": "change",
                "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                "check": "chk_8v1m3n7p4r6s9t0wxyhk5zba2q",
                "requested_scope": {"channels": ["social", "web", "tv"], "final_deliverables": 30},
                "offer": {
                    "type": "flat",
                    "flat": {"amount": 1000000, "currency": "usd"},
                    "schedule": "on_acceptance",
                },
                "note": "We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.",
                "metadata": {"campaign": "trail-winter-tv"},
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/license_requests",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "kind": "change",
                  "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                  "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                  "check": "chk_8v1m3n7p4r6s9t0wxyhk5zba2q",
                  "requested_scope": {
                    "channels": [
                      "social",
                      "web",
                      "tv"
                    ],
                    "final_deliverables": 30
                  },
                  "offer": {
                    "type": "flat",
                    "flat": {
                      "amount": 1000000,
                      "currency": "usd"
                    },
                    "schedule": "on_acceptance"
                  },
                  "note": "We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.",
                  "metadata": {
                    "campaign": "trail-winter-tv"
                  }
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/license_requests", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listLicenseRequests
      summary: List license requests
      x-mint:
        href: /api-reference/license-requests/list-license-requests
        metadata:
          playground: simple
      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).

        Lists the license requests you sent. A representative whose mandate has `issue_licenses`
        also sees the requests addressed to that talent; filter with `talent`.

        Restricted keys need `license_requests:write`.
      tags: [License requests]
      security:
        - { SecretKey: [license_requests:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: talent
          in: query
          description: Only requests to this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: |
            Only requests with this status, such as `sent` for those still waiting for an answer.
          schema: { $ref: "#/components/schemas/LicenseRequestStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of license requests.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRequestList" }
              examples:
                requests_to_talent:
                  summary: A licensee's requests to one talent
                  value:
                    object: list
                    data:
                      - id: lrq_py3xqfvbjjcdhvf33y6c2w26jm
                        object: license_request
                        livemode: true
                        kind: change
                        status: sent
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_revision: null
                        check: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
                        requested_scope:
                          channels:
                            - social
                            - web
                            - tv
                          final_deliverables: 30
                        offer:
                          type: flat
                          flat:
                            amount: 1000000
                            currency: usd
                          schedule: on_acceptance
                        note: We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.
                        decision_note: null
                        signed_at: null
                        declined_at: null
                        withdrawn_at: null
                        metadata:
                          campaign: trail-winter-tv
                        created_at: "2026-10-17T18:10:00Z"
                      - id: lrq_dp9594v61t1wk0mebf6t7dpyae
                        object: license_request
                        livemode: true
                        kind: new
                        status: declined
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        license: null
                        license_revision: null
                        check: null
                        requested_scope:
                          facet_types:
                            - voice
                          modalities:
                            - speech
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - audio
                            - streaming
                          territories:
                            - US
                          starts_at: "2026-11-01T04:00:00Z"
                          ends_at: "2027-02-01T05:00:00Z"
                          final_deliverables: 2
                        offer:
                          type: flat
                          flat:
                            amount: 2000000
                            currency: usd
                          schedule: on_acceptance
                        note: Two 30-second radio and streaming spots for the winter campaign, read in Maya's voice.
                        decision_note: Maya is not licensing her voice for advertising.
                        signed_at: null
                        declined_at: "2026-10-16T12:30:00Z"
                        withdrawn_at: null
                        metadata: {}
                        created_at: "2026-10-14T16:00:00Z"
                      - id: lrq_aja93j66kp1sg4qnepq3wjzk27
                        object: license_request
                        livemode: true
                        kind: new
                        status: signed
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        check: null
                        requested_scope:
                          facet_types:
                            - likeness
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          starts_at: "2026-10-01T04:00:00Z"
                          ends_at: "2027-03-31T04:00:00Z"
                          final_deliverables: 30
                        offer:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                        note: "Trail campaign, October to March: images of Maya on social and our site in the US and Canada."
                        decision_note: Signed for 24 final images. Maya reviews each output before release.
                        signed_at: "2026-09-27T11:15:00Z"
                        declined_at: null
                        withdrawn_at: null
                        metadata: {}
                        created_at: "2026-09-21T14:30:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/license_requests?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_requests?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/license_requests?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/license_requests?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /license_requests/{request_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveLicenseRequest
      summary: Retrieve a license request
      x-mint:
        href: /api-reference/license-requests/retrieve-a-license-request
        metadata:
          playground: simple
      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).

        Returns a license request you sent or, with a mandate that has `issue_licenses`, one
        addressed to a talent you represent. Once it is `signed`, `license_revision` names the
        revision the talent's side signed, which may differ from `requested_scope`.

        Restricted keys need `license_requests:write`.
      tags: [License requests]
      security:
        - { SecretKey: [license_requests:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseRequestId"
      responses:
        "200":
          description: The license request.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRequest" }
              examples:
                signed:
                  summary: A change request the talent signed
                  value:
                    id: lrq_py3xqfvbjjcdhvf33y6c2w26jm
                    object: license_request
                    livemode: true
                    kind: change
                    status: signed
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                    license_revision: lrv_5ecwa673wbbej5a0zkz2vxnk49
                    check: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
                    requested_scope:
                      channels:
                        - social
                        - web
                        - tv
                      final_deliverables: 30
                    offer:
                      type: flat
                      flat:
                        amount: 1000000
                        currency: usd
                      schedule: on_acceptance
                    note: We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.
                    decision_note: TV is approved. The total stays at 24 final outputs.
                    signed_at: "2026-10-20T15:30:00Z"
                    declined_at: null
                    withdrawn_at: null
                    metadata:
                      campaign: trail-winter-tv
                    created_at: "2026-10-17T18:10:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /license_requests/{request_id}/withdraw:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: withdrawLicenseRequest
      summary: Withdraw a license request
      x-mint:
        href: /api-reference/license-requests/withdraw-a-license-request
        metadata:
          playground: simple
      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).

        Withdraws a request the talent has not answered yet.

        Restricted keys need `license_requests:write`.
      tags: [License requests]
      security:
        - { SecretKey: [license_requests:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/LicenseRequestId"
      responses:
        "200":
          description: The withdrawn request.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRequest" }
              examples:
                withdrawn:
                  summary: A withdrawn request
                  value:
                    id: lrq_gcts09q1qwn82q9hz45txyzq4r
                    object: license_request
                    livemode: true
                    kind: new
                    status: withdrawn
                    talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: null
                    license_revision: null
                    check: null
                    requested_scope:
                      facet_types:
                        - likeness
                      modalities:
                        - image
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                      territories:
                        - US
                      starts_at: "2026-11-15T05:00:00Z"
                      ends_at: "2027-01-01T05:00:00Z"
                      final_deliverables: 12
                    offer:
                      type: flat
                      flat:
                        amount: 800000
                        currency: usd
                      schedule: on_acceptance
                    note: Holiday gift guide images on social, US only.
                    decision_note: null
                    signed_at: null
                    declined_at: null
                    withdrawn_at: "2026-10-10T09:15:00Z"
                    metadata: {}
                    created_at: "2026-10-08T13:00:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY:?Set REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/withdraw' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/withdraw", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/withdraw",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_WITHDRAW_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/withdraw", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /license_requests/{request_id}/decline:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: declineLicenseRequest
      summary: Decline a license request
      x-mint:
        href: /api-reference/license-requests/decline-a-license-request
        metadata:
          playground: simple
      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).

        Declines a request addressed to a talent you represent. Needs a mandate with
        `issue_licenses`. The licensee receives `license_request.declined` with your
        `decision_note`. To agree instead, [draft a license](/api-reference/license-drafts/draft-a-license)
        that names the request.

        Restricted keys need `license_requests:write`.
      tags: [License requests]
      security:
        - { SecretKey: [license_requests:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/LicenseRequestId"
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseRequestDecline" }
            examples:
              with_note:
                summary: Decline with a note for the licensee
                value:
                  decision_note: Maya is not licensing her voice for advertising.
      responses:
        "200":
          description: The declined request.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRequest" }
              examples:
                declined:
                  summary: The declined request
                  value:
                    id: lrq_dp9594v61t1wk0mebf6t7dpyae
                    object: license_request
                    livemode: true
                    kind: new
                    status: declined
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: null
                    license_revision: null
                    check: null
                    requested_scope:
                      facet_types:
                        - voice
                      modalities:
                        - speech
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - audio
                        - streaming
                      territories:
                        - US
                      starts_at: "2026-11-01T04:00:00Z"
                      ends_at: "2027-02-01T05:00:00Z"
                      final_deliverables: 2
                    offer:
                      type: flat
                      flat:
                        amount: 2000000
                        currency: usd
                      schedule: on_acceptance
                    note: Two 30-second radio and streaming spots for the winter campaign, read in Maya's voice.
                    decision_note: Maya is not licensing her voice for advertising.
                    signed_at: null
                    declined_at: "2026-10-16T12:30:00Z"
                    withdrawn_at: null
                    metadata: {}
                    created_at: "2026-10-14T16:00:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY:?Set REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/decline' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "decision_note": "Maya is not licensing her voice for advertising."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/decline", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "decision_note": "Maya is not licensing her voice for advertising."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"decision_note": "Maya is not licensing her voice for advertising."}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/decline",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_DECLINE_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "decision_note": "Maya is not licensing her voice for advertising."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/decline", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /connections:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createConnection
      summary: Create a connection
      x-mint:
        href: /api-reference/connections/create-a-connection
        metadata:
          playground: simple
      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).

        Redeems the authorization code that a licensee's approval sends to your redirect URI, and
        creates the connection. Call it from your server with your secret key and the PKCE
        `code_verifier` you created for that approval, within 10 minutes of it. A code works once;
        an unknown, expired or used code, or a verifier or redirect URI that does not match, returns
        `400 authorization_code_invalid`. Then act for the licensee with `Reflections-Account` set
        to the connection's `licensee`. See [Connect a
        licensee](/api-reference/authentication#connect-a-licensee-with-oauth).

        Needs an unrestricted key.
      tags: [Connections]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/ConnectionCreate" }
            examples:
              approved:
                summary: Redeem a licensee's approval
                value:
                  code: ac_Jf3k9QmZ2vX8pT4wR7nY1bL6
                  code_verifier: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
                  redirect_uri: https://northlight.example/oauth/reflections/callback
      responses:
        "200":
          description: The new connection.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Connection" }
              examples:
                active:
                  summary: An active connection with Ridgeline
                  value:
                    id: con_av0baahbfheftkzxqbkns02qwf
                    object: connection
                    livemode: true
                    status: active
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    licensee_name: Ridgeline
                    platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    platform_name: Northlight
                    scopes:
                      - files:write
                      - checks:write
                      - generations:write
                      - usage:write
                    licenses:
                      mode: all
                      ids: []
                    revoked_by: null
                    revoked_at: null
                    created_at: "2026-09-29T10:12:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/connections' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "code": "ac_Jf3k9QmZ2vX8pT4wR7nY1bL6",
              "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
              "redirect_uri": "https://northlight.example/oauth/reflections/callback"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/connections", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "code": "ac_Jf3k9QmZ2vX8pT4wR7nY1bL6",
                "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
                "redirect_uri": "https://northlight.example/oauth/reflections/callback"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "code": "ac_Jf3k9QmZ2vX8pT4wR7nY1bL6",
                "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
                "redirect_uri": "https://northlight.example/oauth/reflections/callback",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/connections",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_CONNECTION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "code": "ac_Jf3k9QmZ2vX8pT4wR7nY1bL6",
                  "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
                  "redirect_uri": "https://northlight.example/oauth/reflections/callback"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/connections", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listConnections
      summary: List connections
      x-mint:
        href: /api-reference/connections/list-connections
        metadata:
          playground: simple
      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).

        Lists connections where the caller is the platform or the licensee. A platform creates one
        with Create a connection after a licensee approves it; see Authentication.

        Needs an unrestricted key.
      tags: [Connections]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: role
          in: query
          description: Your side of the connection.
          schema: { type: string, enum: [platform, licensee] }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of connections.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ConnectionList" }
              examples:
                licensee_connections:
                  summary: A licensee's connections, one active and one ended
                  value:
                    object: list
                    data:
                      - id: con_av0baahbfheftkzxqbkns02qwf
                        object: connection
                        livemode: true
                        status: active
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        licensee_name: Ridgeline
                        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        platform_name: Northlight
                        scopes:
                          - files:write
                          - checks:write
                          - generations:write
                          - usage:write
                        licenses:
                          mode: all
                          ids: []
                        revoked_by: null
                        revoked_at: null
                        created_at: "2026-09-29T10:12:00Z"
                      - id: con_e2fsvabw199qmwhhabm6bbjfa6
                        object: connection
                        livemode: true
                        status: revoked
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        licensee_name: Ridgeline
                        platform: acct_qspdycvcyh26864r80c2nqfnb0
                        platform_name: Kestrel Studio
                        scopes:
                          - files:write
                          - checks:write
                          - generations:write
                        licenses:
                          mode: listed
                          ids:
                            - lic_2xzg3abqbz7fxf5qeaq2fa4d81
                        revoked_by: licensee
                        revoked_at: "2026-10-10T15:00:00Z"
                        created_at: "2026-09-05T11:00:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/connections?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/connections?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/connections?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/connections?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /connections/{connection_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveConnection
      summary: Retrieve a connection
      x-mint:
        href: /api-reference/connections/retrieve-a-connection
        metadata:
          playground: simple
      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).

        Returns a connection where you are the platform or the licensee: the `scopes` the licensee
        approved, and which of its licenses the platform may use.

        Needs an unrestricted key.
      tags: [Connections]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ConnectionId"
      responses:
        "200":
          description: The connection.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Connection" }
              examples:
                active:
                  summary: An active connection
                  value:
                    id: con_av0baahbfheftkzxqbkns02qwf
                    object: connection
                    livemode: true
                    status: active
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    licensee_name: Ridgeline
                    platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    platform_name: Northlight
                    scopes:
                      - files:write
                      - checks:write
                      - generations:write
                      - usage:write
                    licenses:
                      mode: all
                      ids: []
                    revoked_by: null
                    revoked_at: null
                    created_at: "2026-09-29T10:12:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }
    delete:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: deleteConnection
      summary: End a connection
      x-mint:
        href: /api-reference/connections/end-a-connection
        metadata:
          playground: simple
      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).

        Ends a connection. Either side may end it. Checks for the licensee fail with
        `account_not_connected` from that moment, and outstanding authorizations issued under the
        connection stop verifying when they expire.

        Needs an unrestricted key.
      tags: [Connections]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ConnectionId"
      responses:
        "200":
          description: The ended connection.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Connection" }
              examples:
                ended:
                  summary: A connection the licensee ended
                  value:
                    id: con_av0baahbfheftkzxqbkns02qwf
                    object: connection
                    livemode: true
                    status: revoked
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    licensee_name: Ridgeline
                    platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    platform_name: Northlight
                    scopes:
                      - files:write
                      - checks:write
                      - generations:write
                      - usage:write
                    licenses:
                      mode: all
                      ids: []
                    revoked_by: licensee
                    revoked_at: "2026-10-28T16:20:00Z"
                    created_at: "2026-09-29T10:12:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X DELETE 'https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf", {
              method: "DELETE",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf",
                              method="DELETE", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("DELETE", "https://app.reflections.ai/v1/connections/con_av0baahbfheftkzxqbkns02qwf", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /files:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createFile
      summary: Upload a file
      x-mint:
        href: /api-reference/files/upload-a-file
        metadata:
          playground: simple
      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).

        Uploads a reference, voice sample or output. Send the bytes as `multipart/form-data` for
        files up to 100 MB. For larger files, send JSON with the size and `sha256` and upload the
        bytes to the returned `upload_url`. A file is usable when its `status` is `ready`. Files
        expire after 24 hours unless a held generation needs them longer.

        Restricted keys need `files:write`.
      tags: [Files]
      security:
        - { SecretKey: [files:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file, purpose]
              properties:
                file:
                  type: string
                  format: binary
                  description: The bytes.
                purpose: { $ref: "#/components/schemas/FilePurpose" }
          application/json:
            schema: { $ref: "#/components/schemas/FileCreate" }
            examples:
              large_output:
                summary: A video output over 100 MB
                value:
                  purpose: output
                  size: 241587113
                  sha256: 2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373
                  media_type: video/mp4
                  filename: ridge-trail.mp4
      responses:
        "200":
          description: The file.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/File" }
              examples:
                uploading:
                  summary: Created with JSON, waiting for its bytes
                  value:
                    id: file_y04rz07dh5k83ff2g4n1wtvgy7
                    object: file
                    livemode: true
                    purpose: output
                    status: uploading
                    sha256: 2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373
                    media_type: video/mp4
                    size: 241587113
                    width: null
                    height: null
                    duration_ms: null
                    upload_url: https://uploads.reflections.ai/file_y04rz07dh5k83ff2g4n1wtvgy7?expires=1792266127&signature=d33ef9140593995ffc3d0602234e8d46d86678cc63b
                    expires_at: "2026-10-18T18:42:07Z"
                    created_at: "2026-10-17T18:42:07Z"
                ready:
                  summary: Uploaded as multipart, ready to use
                  value:
                    id: file_7h3k9m2p4q6r8s1t3v5w7x9yza
                    object: file
                    livemode: true
                    purpose: reference
                    status: ready
                    sha256: 7c1e3a5b9d2f4e6a8c0b2d4f6e8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a
                    media_type: image/png
                    size: 3284117
                    width: 1024
                    height: 1536
                    duration_ms: null
                    upload_url: null
                    expires_at: "2026-10-18T17:58:41Z"
                    created_at: "2026-10-17T17:58:41Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/Conflict" }
        "413": { $ref: "#/components/responses/PayloadTooLarge" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/files' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "purpose": "output",
              "size": 241587113,
              "sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
              "media_type": "video/mp4",
              "filename": "ridge-trail.mp4"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/files", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "purpose": "output",
                "size": 241587113,
                "sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
                "media_type": "video/mp4",
                "filename": "ridge-trail.mp4"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "purpose": "output",
                "size": 241587113,
                "sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
                "media_type": "video/mp4",
                "filename": "ridge-trail.mp4",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/files",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_FILE_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "purpose": "output",
                  "size": 241587113,
                  "sha256": "2d792ec6ff98b0311e835c38449522860bc81bcf2c6919f6d60dcf7e20a55373",
                  "media_type": "video/mp4",
                  "filename": "ridge-trail.mp4"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/files", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /files/{file_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveFile
      summary: Retrieve a file
      x-mint:
        href: /api-reference/files/retrieve-a-file
        metadata:
          playground: simple
      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).

        Returns a file. After a JSON upload, read it until `status` is `ready`, then send its ID in
        a check's `inputs` or a generation's `artifact`.

        Restricted keys need `files:write`.
      tags: [Files]
      security:
        - { SecretKey: [files:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: file_id
          in: path
          required: true
          description: The file's ID, `file_…`.
          example: file_8q0r2s4t6v8w0x2y4z6a8b0c2d
          schema: { type: string, pattern: "^file_[0-9a-hjkmnp-tv-z]{26}$" }
      responses:
        "200":
          description: The file.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/File" }
              examples:
                ready:
                  summary: A rendered voice line, ready
                  value:
                    id: file_8q0r2s4t6v8w0x2y4z6a8b0c2d
                    object: file
                    livemode: true
                    purpose: output
                    status: ready
                    sha256: 3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d
                    media_type: audio/wav
                    size: 326444
                    width: null
                    height: null
                    duration_ms: 3400
                    upload_url: null
                    expires_at: "2026-10-18T18:05:58Z"
                    created_at: "2026-10-17T18:05:58Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/files/file_8q0r2s4t6v8w0x2y4z6a8b0c2d' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/files/file_8q0r2s4t6v8w0x2y4z6a8b0c2d", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/files/file_8q0r2s4t6v8w0x2y4z6a8b0c2d",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/files/file_8q0r2s4t6v8w0x2y4z6a8b0c2d", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /checks:
    post:
      x-reflections-availability: { test: available, live: available }
      operationId: createCheck
      summary: Create a check
      x-mint:
        href: /api-reference/checks/create-a-check
      description: |
        **Test mode available. Live mode available when configured.** This describes source support;
        production activation is not established. Until activation, a live key receives `403`
        [`live_not_activated`](/api-reference/errors#live_not_activated); do not retry it. Sandbox
        checks evaluate fictional fixtures and text inputs; see [Sandbox](/sandbox).

        The initial live implementation requires one explicit owned `license`, text inputs totaling
        at most 64 KiB, image depiction for commercial advertising or branded content, one candidate,
        and `on_escalate: "deny"`. Every channel and territory must match the signed scope; only
        signed `WW` means worldwide. Declare `execution.provider` and `execution.model` for the
        later output. `job_id` is optional. Reference media, talent/facet selection, end users,
        reuse and nondefault prompt handling are unsupported.

        The license must newly sign `externalCreation: "images.v1"` and
        `externalCreationPostRevocation: "retain"`. Live signing requires protected activation after
        the public key's 30-day publication period. Send an `Idempotency-Key`; while evaluation is
        pending, retry `409 idempotency_key_in_use` with the same body and key. Retries never start
        another paid evaluation. See [the initial live image journey](/guides/image-and-video-platforms#initial-live-image-implementation).

        **Broader protocol contract:** the remaining description and examples include planned
        forms beyond that initial live implementation.

        Decides whether a use of a talent may proceed, before you generate anything. Send the
        request your model will actually receive: the user's prompt, any system text you add, your
        rewritten prompt, and every reference.

        The response always has a `decision`:

        - `allow`: generate, and meet every obligation, including `generation_check`.
        - `deny`: do not generate. `reasons` say why in the license's own words; `remedy` says what
          would change the answer.
        - `escalate`: do not generate yet. A person with authority will decide. Listen for
          `check.resolved` or poll this check. An unanswered escalation becomes `deny` at
          `escalation.expires_at`.

        Reflections resolves the inputs of every check. Talent named in `talent` are matched as
        `explicit`, and anyone else the inputs name or show is added. If no protected talent is
        found, the decision is `allow` with `talent: []` and no obligations. Reflections checks only the talent
        the check resolves; it does not screen outputs for talent nobody named.

        Restricted keys need `checks:write`.
      tags: [Checks]
      security:
        - { SecretKey: [checks:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CheckCreate" }
            examples:
              sandbox_image:
                summary: Supported sandbox request (replace object IDs with your own)
                value: { "inputs": [{ "role": "prompt", "text": "Maya Okafor running a mountain trail at sunrise" }], "use": { "modality": "image", "kind": "depiction", "purpose": "advertising", "commercial": true, "channels": ["social"], "territories": ["US"] }, "execution": { "provider": "sandbox-fixture", "model": "one-pixel-png", "candidates": 1 } }
              image_ad:
                summary: An image for an ad
                value:
                  inputs:
                    - role: prompt
                      text: "Maya Okafor holding our new trail shoe on a rocky ridge at sunrise"
                    - role: rewritten_prompt
                      text: "Photoreal portrait of Maya Okafor, golden-hour light, holding a grey trail running shoe, rocky ridge, wide shot"
                    - role: reference
                      file: file_7h3k9m2p4q6r8s1t3v5w7x9yza
                  use:
                    modality: image
                    kind: depiction
                    purpose: advertising
                    commercial: true
                    channels: [social, web]
                    territories: [US, CA]
                  end_user:
                    id: usr_48213
                  execution:
                    provider: example-image-provider
                    model: image-model-3
                    candidates: 4
                  on_escalate: hold
              voice_line:
                summary: A speech line in a licensed voice
                value:
                  talent: [tal_9t0wxyhk5zba2q8v1m3n7p4r6s]
                  inputs:
                    - role: script
                      text: "Welcome back to the Ridge Runners podcast."
                  use:
                    modality: speech
                    kind: impersonation
                    purpose: branded_content
                    commercial: true
                    channels: [audio, web]
                    territories: [US]
                  execution:
                    provider: example-voice-provider
                    model: tts-2
                    candidates: 1
                  on_escalate: deny
      responses:
        "200":
          description: The check, with its decision.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Check" }
              examples:
                allow: { $ref: "#/components/examples/CheckAllow" }
                deny: { $ref: "#/components/examples/CheckDeny" }
                escalate: { $ref: "#/components/examples/CheckEscalate" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "413": { $ref: "#/components/responses/PayloadTooLarge" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/checks' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "inputs": [
                {
                  "role": "prompt",
                  "text": "Maya Okafor running a mountain trail at sunrise"
                }
              ],
              "use": {
                "modality": "image",
                "kind": "depiction",
                "purpose": "advertising",
                "commercial": true,
                "channels": [
                  "social"
                ],
                "territories": [
                  "US"
                ]
              },
              "execution": {
                "provider": "sandbox-fixture",
                "model": "one-pixel-png",
                "candidates": 1
              }
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/checks", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "inputs": [
                  {
                    "role": "prompt",
                    "text": "Maya Okafor running a mountain trail at sunrise"
                  }
                ],
                "use": {
                  "modality": "image",
                  "kind": "depiction",
                  "purpose": "advertising",
                  "commercial": true,
                  "channels": [
                    "social"
                  ],
                  "territories": [
                    "US"
                  ]
                },
                "execution": {
                  "provider": "sandbox-fixture",
                  "model": "one-pixel-png",
                  "candidates": 1
                }
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "inputs": [{"role": "prompt", "text": "Maya Okafor running a mountain trail at sunrise"}],
                "use": {
                    "modality": "image",
                    "kind": "depiction",
                    "purpose": "advertising",
                    "commercial": True,
                    "channels": ["social"],
                    "territories": ["US"],
                },
                "execution": {"provider": "sandbox-fixture", "model": "one-pixel-png", "candidates": 1},
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/checks",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_CHECK_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "inputs": [
                    {
                      "role": "prompt",
                      "text": "Maya Okafor running a mountain trail at sunrise"
                    }
                  ],
                  "use": {
                    "modality": "image",
                    "kind": "depiction",
                    "purpose": "advertising",
                    "commercial": true,
                    "channels": [
                      "social"
                    ],
                    "territories": [
                      "US"
                    ]
                  },
                  "execution": {
                    "provider": "sandbox-fixture",
                    "model": "one-pixel-png",
                    "candidates": 1
                  }
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/checks", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: listChecks
      summary: List checks
      x-mint:
        href: /api-reference/checks/list-checks
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Returns your checks, newest first. Filter by `decision`, `status`, `talent` or
        `created_after`; `status=escalated` lists the checks still waiting for a person.

        Restricted keys need `checks:write`.
      tags: [Checks]
      security:
        - { SecretKey: [checks:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: decision
          in: query
          description: Only checks with this decision.
          schema: { $ref: "#/components/schemas/Decision" }
        - name: status
          in: query
          description: Only checks with this status, such as `escalated`.
          schema: { $ref: "#/components/schemas/CheckStatus" }
        - name: talent
          in: query
          description: Only checks that invoked this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: created_after
          in: query
          description: Only checks created after this time.
          schema: { type: string, format: date-time }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of checks.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/CheckList" }
              examples:
                escalated:
                  summary: Checks still waiting for a person
                  value:
                    object: list
                    data:
                      - id: chk_3pg20xkepkscyp0qbpc4yq7ad2
                        object: check
                        livemode: true
                        status: escalated
                        decision: escalate
                        talent:
                          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                            name: Maya Okafor
                            matched_by: name
                            confidence: high
                            decision: escalate
                            facets:
                              - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                            license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                            license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                            terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                            escalation: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                        use:
                          modality: image
                          kind: depiction
                          purpose: advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                        reasons:
                          - code: evaluation_unavailable
                            stage: check
                            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                            sentence: This request could not be checked in time, so Maya Okafor's side will review it.
                        obligations: []
                        authorization: null
                        escalation:
                          id: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                          reason: evaluation_unavailable
                          reviewer: talent
                          status: open
                          expires_at: "2026-10-27T09:41:00Z"
                          resolved_at: null
                          note: null
                        remedy: null
                        request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        session: null
                        receipt: null
                        metadata: {}
                        created_at: "2026-10-20T09:41:00Z"
                      - id: chk_x3n8earfjvqsnts9ryqtzet3a4
                        object: check
                        livemode: true
                        status: escalated
                        decision: escalate
                        talent:
                          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                            name: Maya Okafor
                            matched_by: name
                            confidence: high
                            decision: escalate
                            facets:
                              - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                            license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                            license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                            terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                            escalation: esc_0m3es8rwstwndrxyxkv3z856zr
                        use:
                          modality: image
                          kind: depiction
                          purpose: advertising
                          commercial: true
                          channels:
                            - social
                          territories:
                            - US
                        reasons:
                          - code: unverifiable_request
                            stage: check
                            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                            term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            sentence: "Keep Maya Okafor the same person: face, skin tone and build unchanged."
                        obligations: []
                        authorization: null
                        escalation:
                          id: esc_0m3es8rwstwndrxyxkv3z856zr
                          reason: unverifiable
                          reviewer: talent
                          status: open
                          expires_at: "2026-10-26T16:05:00Z"
                          resolved_at: null
                          note: null
                        remedy: null
                        request_digest: sha256:3ae7c80e6bc98eda19b2727e30df26d51342e7a60bacf27c63f25636136c2ae3
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        session: null
                        receipt: null
                        metadata: {}
                        created_at: "2026-10-19T16:05:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/checks?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/checks?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/checks?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/checks?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /checks/{check_id}:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveCheck
      summary: Retrieve a check
      x-mint:
        href: /api-reference/checks/retrieve-a-check
      description: |
        **Test mode available. Live mode available when configured.** Source support does not
        establish production activation. Live reads return the caller's check, including current
        authorization consumption or expiry. Pending evaluation returns
        `409 idempotency_key_in_use`; wait before retrying. Private details remain available while
        pending and for 24 hours after their terminal retention boundary, then return `404`.
        A check linked to a pending generation remains available through that generation's window.

        In the sandbox and broader protocol, poll an `escalated` check at most once every 5 seconds.
        The initial live implementation requires `on_escalate: "deny"` and has no request review hold.

        Restricted keys need `checks:write`.
      tags: [Checks]
      security:
        - { SecretKey: [checks:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/CheckId"
      responses:
        "200":
          description: The check.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Check" }
              examples:
                escalated:
                  summary: A check waiting for a reviewer
                  value:
                    id: chk_3pg20xkepkscyp0qbpc4yq7ad2
                    object: check
                    livemode: true
                    status: escalated
                    decision: escalate
                    talent:
                      - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        name: Maya Okafor
                        matched_by: name
                        confidence: high
                        decision: escalate
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                        escalation: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                    use:
                      modality: image
                      kind: depiction
                      purpose: advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                        - CA
                    reasons:
                      - code: evaluation_unavailable
                        stage: check
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        sentence: This request could not be checked in time, so Maya Okafor's side will review it.
                    obligations: []
                    authorization: null
                    escalation:
                      id: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                      reason: evaluation_unavailable
                      reviewer: talent
                      status: open
                      expires_at: "2026-10-27T09:41:00Z"
                      resolved_at: null
                      note: null
                    remedy: null
                    request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    session: null
                    receipt: null
                    metadata: {}
                    created_at: "2026-10-20T09:41:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /checks/{check_id}/cancel:
    post:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: cancelCheck
      summary: Cancel a check
      x-mint:
        href: /api-reference/checks/cancel-a-check
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Cancels an escalated check you no longer need, such as when your user leaves. The reviewer
        is told, and the check's `status` becomes `cancelled`. Allowed checks can be cancelled to
        void their authorization early.

        Restricted keys need `checks:write`.
      tags: [Checks]
      security:
        - { SecretKey: [checks:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/CheckId"
      responses:
        "200":
          description: The cancelled check.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Check" }
              examples:
                cancelled:
                  summary: An escalated check, cancelled
                  value:
                    id: chk_x3n8earfjvqsnts9ryqtzet3a4
                    object: check
                    livemode: true
                    status: cancelled
                    decision: escalate
                    talent:
                      - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        name: Maya Okafor
                        matched_by: name
                        confidence: high
                        decision: escalate
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                        escalation: esc_0m3es8rwstwndrxyxkv3z856zr
                    use:
                      modality: image
                      kind: depiction
                      purpose: advertising
                      commercial: true
                      channels:
                        - social
                      territories:
                        - US
                    reasons:
                      - code: unverifiable_request
                        stage: check
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                        sentence: "Keep Maya Okafor the same person: face, skin tone and build unchanged."
                    obligations: []
                    authorization: null
                    escalation:
                      id: esc_0m3es8rwstwndrxyxkv3z856zr
                      reason: unverifiable
                      reviewer: talent
                      status: cancelled
                      expires_at: "2026-10-26T16:05:00Z"
                      resolved_at: "2026-10-20T10:30:00Z"
                      note: null
                    remedy: null
                    request_digest: sha256:3ae7c80e6bc98eda19b2727e30df26d51342e7a60bacf27c63f25636136c2ae3
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    session: null
                    receipt: null
                    metadata: {}
                    created_at: "2026-10-19T16:05:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY:?Set REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2/cancel' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2/cancel", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2/cancel",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CANCEL_CHECK_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/checks/chk_3pg20xkepkscyp0qbpc4yq7ad2/cancel", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /generations:
    post:
      x-reflections-availability: { test: available, live: available }
      operationId: createGeneration
      summary: Create a generation
      x-mint:
        href: /api-reference/generations/create-a-generation
      description: |
        **Test mode available. Live mode available when configured.** Source support does not
        establish production activation. Until activation, a live key receives `403`
        [`live_not_activated`](/api-reference/errors#live_not_activated). Sandbox decisions are simulated; inline base64 or
        SHA-256 attestation is supported, but file IDs and URL fetching are not.

        The initial live implementation accepts one inline, still PNG, at most 7 MiB
        (7,340,032 decoded bytes), in a JSON body of at most 10 MiB. Send its exact lowercase
        SHA-256, `candidate_index: 0`, and the check's declared provider and model. A supplied
        candidate count must be one; `job_id` is optional and may be assigned after the provider
        starts. Digest-only attestation, files, URLs, sessions, video, audio, transcripts and
        watermark inputs are unsupported. Reflections evaluates the submitted bytes; it does not
        render or fetch the output.

        Send an `Idempotency-Key`. The same caller key must hold both `checks:write` and
        `generations:write`. Live admission requires the new signed external-image and retention
        terms and an activated live signer, as described for [checks](/api-reference/checks/create-a-check).
        Send the allowed `check` ID; the server reads its stored authorization token. There is
        no separate token field in this request. The first successful submission must arrive
        before `authorization.expires_at`, even if the provider job started earlier; otherwise
        it fails with `409 check_expired`.
        A successful POST always returns the immutable accepted `202` response, including on
        replay. Poll the generation for `checking`, `held`, `released`, `denied` or `expired`.
        Every image requires the talent's actual release before `decision: "allow"`; upload or
        evaluator success alone never permits delivery. No live webhooks are delivered.

        **Broader protocol contract:** the remaining description and examples include planned
        forms beyond that initial live implementation.

        Checks an output before anyone sees it.

        The output is checked against the license its `check` relied on: the bytes are bound to the
        check and candidate, and the talent's protected attributes and rules are checked on the
        bytes. Only the talent the check covered are checked. Every generation names a `check`, or
        a `session` for an output made in a live session.

        Images, speech up to 60 seconds and text return a decision in the response. Video and longer
        audio return `status: checking`, and the decision arrives as `generation.allowed` or
        `generation.denied`. When the license has a person release every output, they return
        `status: held` instead, and the decision arrives as `generation.released` or
        `generation.denied`.

        Deliver nothing until the decision is `allow`. Embed the `c2pa` assertion in the output's C2PA
        manifest before you deliver it.

        Restricted keys need `generations:write`.
      tags: [Generations]
      security:
        - { SecretKey: [generations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenerationCreate" }
            examples:
              sandbox_inline_png:
                summary: Supported sandbox request (replace object IDs with your own)
                value: { "check": "chk_3m7p4r6s9t0wxyhk5zba2q8v1n", "candidate_index": 0, "artifact": { "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg==", "sha256": "20c1e1ec7a62d54fe8191b5c509e7a2c88b520a429bc1b74c55e7ccf72cbcc6d", "media_type": "image/png" } }
              enforce:
                summary: An output under a check
                value:
                  check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                  candidate_index: 0
                  artifact:
                    file: file_2c4e6g8j0k2m4n6p8q0r2s4t6v
                    sha256: 9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a
                  execution:
                    provider: example-image-provider
                    model: image-model-3
                    job_id: job_88213
      responses:
        "200":
          description: The generation.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Generation" }
              examples:
                held: { $ref: "#/components/examples/GenerationHeld" }
                allowed: { $ref: "#/components/examples/GenerationAllowed" }
                denied: { $ref: "#/components/examples/GenerationDenied" }
        "202":
          description: The initial live image submission's immutable accepted object. POST retries replay this response; GET the generation for evaluation, talent review and its final decision.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Generation" }
              examples:
                live_accepted:
                  summary: Accepted for live image evaluation, pending talent release
                  value:
                    id: gen_6s9t0wxyhk5zba2q8v1m3n7p4r
                    object: generation
                    livemode: true
                    check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                    session: null
                    candidate_index: 0
                    status: checking
                    decision: null
                    artifact:
                      file: null
                      sha256: 20c1e1ec7a62d54fe8191b5c509e7a2c88b520a429bc1b74c55e7ccf72cbcc6d
                      media_type: image/png
                      duration_ms: null
                    execution:
                      provider: example-image-provider
                      model: image-model-3
                    findings: []
                    unchecked_terms: []
                    reasons: []
                    obligations: []
                    escalation: null
                    assurance: attested
                    receipt: null
                    c2pa: null
                    watermark: null
                    metadata: {}
                    created_at: "2026-10-18T18:00:12Z"
                    decided_at: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "413": { $ref: "#/components/responses/PayloadTooLarge" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/generations' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "check": "chk_3m7p4r6s9t0wxyhk5zba2q8v1n",
              "candidate_index": 0,
              "artifact": {
                "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg==",
                "sha256": "20c1e1ec7a62d54fe8191b5c509e7a2c88b520a429bc1b74c55e7ccf72cbcc6d",
                "media_type": "image/png"
              }
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/generations", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "check": "chk_3m7p4r6s9t0wxyhk5zba2q8v1n",
                "candidate_index": 0,
                "artifact": {
                  "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg==",
                  "sha256": "20c1e1ec7a62d54fe8191b5c509e7a2c88b520a429bc1b74c55e7ccf72cbcc6d",
                  "media_type": "image/png"
                }
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "check": "chk_3m7p4r6s9t0wxyhk5zba2q8v1n",
                "candidate_index": 0,
                "artifact": {
                    "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg==",
                    "sha256": "20c1e1ec7a62d54fe8191b5c509e7a2c88b520a429bc1b74c55e7ccf72cbcc6d",
                    "media_type": "image/png",
                },
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/generations",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_GENERATION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "check": "chk_3m7p4r6s9t0wxyhk5zba2q8v1n",
                  "candidate_index": 0,
                  "artifact": {
                    "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAADUlEQVQImWP4////fwAJ+wP9CNHoHgAAAABJRU5ErkJggg==",
                    "sha256": "20c1e1ec7a62d54fe8191b5c509e7a2c88b520a429bc1b74c55e7ccf72cbcc6d",
                    "media_type": "image/png"
                  }
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/generations", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: listGenerations
      summary: List generations
      x-mint:
        href: /api-reference/generations/list-generations
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Lists your generations. A representative whose mandate has `review_outputs` or
        `receive_statements` sees every generation under the talent's licenses, for audit.

        Restricted keys need `generations:write` or `generations:read`.
      tags: [Generations]
      security:
        - { SecretKey: [generations:write] }
        - { SecretKey: [generations:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: talent
          in: query
          description: Only generations checked for this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: license
          in: query
          description: Only generations made under this license.
          schema: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: check
          in: query
          description: Only generations made under this check.
          schema: { type: string, pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: Only generations with this status, such as `held`.
          schema: { $ref: "#/components/schemas/GenerationStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of generations.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/GenerationList" }
              examples:
                by_check:
                  summary: Outputs submitted under one check
                  value:
                    object: list
                    data:
                      - id: gen_t6v8w0x2y4z6a8b0c2d4e6f8g0
                        object: generation
                        livemode: true
                        check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                        session: null
                        candidate_index: 1
                        status: denied
                        decision: deny
                        artifact:
                          file: file_3t5v7x9z1b3d5f7h9k1m3p5r7s
                          sha256: 4c6e8a0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c
                          media_type: image/png
                          duration_ms: null
                        execution:
                          provider: example-image-provider
                          model: image-model-3
                          job_id: job_88214
                        findings:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            attribute: identity.samePerson
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            rule: Do not show alcohol or tobacco.
                            result: violated
                            detail: A wine glass on the café table.
                        unchecked_terms: []
                        reasons:
                          - code: prohibited_custom_term
                            stage: generation
                            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                            term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            sentence: Do not show alcohol or tobacco.
                        obligations: []
                        escalation: null
                        assurance: observed
                        receipt: rcpt_w0x2y4z6a8b0c2d4e6f8g0h2j4
                        c2pa: null
                        watermark: null
                        metadata: {}
                        created_at: "2026-10-17T18:08:40Z"
                        decided_at: "2026-10-17T18:08:41Z"
                      - id: gen_27anw6frbr27snr28r4rtby65t
                        object: generation
                        livemode: true
                        check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                        session: null
                        candidate_index: 3
                        status: held
                        decision: escalate
                        artifact:
                          file: file_qd3fjw5kzmxmsej34ccjbb3te2
                          sha256: 1f515e0ac5910efaf0ed6a4477f38775ad9dcc6ccb5070f421a0fe85d49867d7
                          media_type: image/png
                          duration_ms: null
                        execution:
                          provider: example-image-provider
                          model: image-model-3
                          job_id: job_88216
                        findings:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            attribute: identity.samePerson
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                            attribute: appearance.wardrobe
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            rule: Do not show alcohol or tobacco.
                            result: preserved
                        unchecked_terms: []
                        reasons: []
                        obligations:
                          - type: hold_until_release
                            reviewer: talent
                          - type: draft_watermark
                        escalation:
                          id: esc_fxr2jmbkavw2sqhgjp78qw9nt7
                          reason: release_review
                          reviewer: talent
                          status: open
                          expires_at: "2026-10-24T18:04:10Z"
                          resolved_at: null
                          note: null
                        assurance: observed
                        receipt: null
                        c2pa: null
                        watermark: null
                        metadata: {}
                        created_at: "2026-10-17T18:04:10Z"
                        decided_at: null
                      - id: gen_0syye78tm8qdvre87y0wnvmfcs
                        object: generation
                        livemode: true
                        check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                        session: null
                        candidate_index: 2
                        status: held
                        decision: escalate
                        artifact:
                          file: file_cf9vex7e3amaf4ph46kks9mp4w
                          sha256: a75e83bb3668a35e7ecf2c2ad75f65999ac134519348cc4d2981030353c0930b
                          media_type: image/png
                          duration_ms: null
                        execution:
                          provider: example-image-provider
                          model: image-model-3
                          job_id: job_88215
                        findings:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            attribute: identity.samePerson
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                            attribute: appearance.wardrobe
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            rule: Do not show alcohol or tobacco.
                            result: preserved
                        unchecked_terms: []
                        reasons: []
                        obligations:
                          - type: hold_until_release
                            reviewer: talent
                          - type: draft_watermark
                        escalation:
                          id: esc_f5zx603y7xn526k4asxrdtasxj
                          reason: release_review
                          reviewer: talent
                          status: open
                          expires_at: "2026-10-24T18:03:05Z"
                          resolved_at: null
                          note: null
                        assurance: observed
                        receipt: null
                        c2pa: null
                        watermark: null
                        metadata: {}
                        created_at: "2026-10-17T18:03:05Z"
                        decided_at: null
                    has_more: true
                    next_cursor: Z2VuXzBzeXllNzh0bThxZHZyZTg3eTB3bnZtZmNz
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/generations?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/generations?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/generations?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/generations?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /generations/{generation_id}:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveGeneration
      summary: Retrieve a generation
      x-mint:
        href: /api-reference/generations/retrieve-a-generation
      description: |
        **Test mode available. Live mode available when configured.** Source support does not
        establish production activation. The initial live implementation returns the caller's
        generation as `checking`, `held`, `released`, `denied` or `expired`. Only the talent's
        committed release permits `decision: "allow"`. Poll this operation for current state;
        replaying the POST returns its original accepted `202` response.
        Private details remain available while pending and for 24 hours after their terminal
        retention boundary, then return `404`. Signed receipts have a separate seven-year lifetime.

        Returns a generation. Read it for the decision on an output that is `checking` or `held`, or
        to read its `c2pa` assertion again.

        Restricted keys need `generations:write` or `generations:read`.
      tags: [Generations]
      security:
        - { SecretKey: [generations:write] }
        - { SecretKey: [generations:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/GenerationId"
      responses:
        "200":
          description: The generation.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Generation" }
              examples:
                allowed:
                  summary: An allowed voice line with its receipt
                  value:
                    id: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
                    object: generation
                    livemode: true
                    check: chk_m3n7p4r6s9t0wxyhk5zba2q8v1
                    session: null
                    candidate_index: 0
                    status: allowed
                    decision: allow
                    artifact:
                      file: file_8q0r2s4t6v8w0x2y4z6a8b0c2d
                      sha256: 3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d
                      media_type: audio/wav
                      duration_ms: 3400
                    execution:
                      provider: example-voice-provider
                      model: tts-2
                      job_id: job_90417
                    findings:
                      - term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.requiredAttributes
                        attribute: identity.samePerson
                        result: preserved
                      - term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                        rule: Do not discuss politics or religion.
                        result: preserved
                    unchecked_terms: []
                    reasons: []
                    obligations:
                      - type: disclosure
                        level: licensed
                        placement: metadata
                        text: AI voice of Maya Okafor, licensed.
                      - type: c2pa_manifest
                      - type: usage_report
                        units: seconds
                        within: P1D
                    escalation: null
                    assurance: observed
                    receipt: rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
                    c2pa:
                      label: ai.reflections.license
                      data:
                        receipt: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg
                        verify_url: https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
                    watermark: null
                    metadata: {}
                    created_at: "2026-10-17T18:06:02Z"
                    decided_at: "2026-10-17T18:06:03Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /generations/{generation_id}/withdraw:
    post:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: withdrawGeneration
      summary: Withdraw a generation
      x-mint:
        href: /api-reference/generations/withdraw-a-generation
      description: |
        **Test mode available. Live mode unavailable.** Uses fictional sandbox data only. See [Sandbox](/sandbox) for the supported forms and limits.

        Withdraws an output from review, or records that a released output is no longer in use. A
        held output that is withdrawn returns its delivery to the license's delivery limit.

        The generation's `status` becomes `withdrawn`. Its receipt's `use_status` does not change: on a
        receipt, `withdrawn` means a revocation requires the output to be taken down, which only the
        talent's revocation sets.

        Restricted keys need `generations:write`.
      tags: [Generations]
      security:
        - { SecretKey: [generations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/GenerationId"
      responses:
        "200":
          description: The withdrawn generation.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Generation" }
              examples:
                withdrawn:
                  summary: A held output, withdrawn
                  value:
                    id: gen_0syye78tm8qdvre87y0wnvmfcs
                    object: generation
                    livemode: true
                    check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                    session: null
                    candidate_index: 2
                    status: withdrawn
                    decision: escalate
                    artifact:
                      file: file_cf9vex7e3amaf4ph46kks9mp4w
                      sha256: a75e83bb3668a35e7ecf2c2ad75f65999ac134519348cc4d2981030353c0930b
                      media_type: image/png
                      duration_ms: null
                    execution:
                      provider: example-image-provider
                      model: image-model-3
                      job_id: job_88215
                    findings:
                      - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                        attribute: identity.samePerson
                        result: preserved
                      - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                        attribute: appearance.wardrobe
                        result: preserved
                      - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                        rule: Do not show alcohol or tobacco.
                        result: preserved
                    unchecked_terms: []
                    reasons: []
                    obligations:
                      - type: hold_until_release
                        reviewer: talent
                      - type: draft_watermark
                    escalation:
                      id: esc_f5zx603y7xn526k4asxrdtasxj
                      reason: release_review
                      reviewer: talent
                      status: cancelled
                      expires_at: "2026-10-24T18:03:05Z"
                      resolved_at: "2026-10-18T09:15:00Z"
                      note: null
                    assurance: observed
                    receipt: null
                    c2pa: null
                    watermark: null
                    metadata: {}
                    created_at: "2026-10-17T18:03:05Z"
                    decided_at: null
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY:?Set REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba/withdraw' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba/withdraw", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba/withdraw",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_WITHDRAW_GENERATION_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/generations/gen_2q8v1m3n7p4r6s9t0wxyhk5zba/withdraw", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /sessions:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createSession
      summary: Create a session
      x-mint:
        href: /api-reference/sessions/create-a-session
        metadata:
          playground: simple
      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).

        Starts a live voice or video session. Reflections runs a check on the session's inputs and,
        if it allows, returns a session token that expires in 5 minutes. Renew it every
        `renew_every`, submit samples at the `sampling` rate, and stay connected to `stream_url` to
        receive `session.terminated`.

        Sessions never escalate: anything that would escalate is `deny`. A license that holds every
        output for release cannot start a session (`session_not_permitted`).

        Restricted keys need `sessions:write`.
      tags: [Sessions]
      security:
        - { SecretKey: [sessions:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/SessionCreate" }
            examples:
              fan_voice_chat:
                summary: A live fan voice chat
                value:
                  talent: [tal_9t0wxyhk5zba2q8v1m3n7p4r6s]
                  facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                  use:
                    modality: speech
                    kind: impersonation
                    purpose: personal
                    commercial: false
                    channels: [in_app]
                    territories: [US]
                  inputs:
                    - role: system
                      text: "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
                  end_user:
                    id: usr_48213
                  execution:
                    provider: example-voice-provider
                    model: realtime-voice-2
      responses:
        "200":
          description: The session. If `status` is `denied`, the check's reasons explain why and no token is issued.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Session" }
              examples:
                active: { $ref: "#/components/examples/SessionActive" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/sessions' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "talent": [
                "tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
              ],
              "facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
              "use": {
                "modality": "speech",
                "kind": "impersonation",
                "purpose": "personal",
                "commercial": false,
                "channels": [
                  "in_app"
                ],
                "territories": [
                  "US"
                ]
              },
              "inputs": [
                {
                  "role": "system",
                  "text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
                }
              ],
              "end_user": {
                "id": "usr_48213"
              },
              "execution": {
                "provider": "example-voice-provider",
                "model": "realtime-voice-2"
              }
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/sessions", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "talent": [
                  "tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
                ],
                "facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
                "use": {
                  "modality": "speech",
                  "kind": "impersonation",
                  "purpose": "personal",
                  "commercial": false,
                  "channels": [
                    "in_app"
                  ],
                  "territories": [
                    "US"
                  ]
                },
                "inputs": [
                  {
                    "role": "system",
                    "text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
                  }
                ],
                "end_user": {
                  "id": "usr_48213"
                },
                "execution": {
                  "provider": "example-voice-provider",
                  "model": "realtime-voice-2"
                }
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "talent": ["tal_9t0wxyhk5zba2q8v1m3n7p4r6s"],
                "facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
                "use": {
                    "modality": "speech",
                    "kind": "impersonation",
                    "purpose": "personal",
                    "commercial": False,
                    "channels": ["in_app"],
                    "territories": ["US"],
                },
                "inputs": [
                    {
                        "role": "system",
                        "text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone.",
                    },
                ],
                "end_user": {"id": "usr_48213"},
                "execution": {"provider": "example-voice-provider", "model": "realtime-voice-2"},
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/sessions",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_SESSION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "talent": [
                    "tal_9t0wxyhk5zba2q8v1m3n7p4r6s"
                  ],
                  "facet": "fct_v1m3n7p4r6s9t0wxyhk5zba2q8",
                  "use": {
                    "modality": "speech",
                    "kind": "impersonation",
                    "purpose": "personal",
                    "commercial": false,
                    "channels": [
                      "in_app"
                    ],
                    "territories": [
                      "US"
                    ]
                  },
                  "inputs": [
                    {
                      "role": "system",
                      "text": "You are a fan voice chat. Speak as Maya Okafor in a friendly tone."
                    }
                  ],
                  "end_user": {
                    "id": "usr_48213"
                  },
                  "execution": {
                    "provider": "example-voice-provider",
                    "model": "realtime-voice-2"
                  }
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/sessions", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /sessions/{session_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveSession
      summary: Retrieve a session
      x-mint:
        href: /api-reference/sessions/retrieve-a-session
        metadata:
          playground: simple
      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).

        Returns a session. If the session stream drops, read the session before you reconnect: a
        termination you missed shows as `status: terminated` with `termination`.

        Restricted keys need `sessions:write`.
      tags: [Sessions]
      security:
        - { SecretKey: [sessions:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: The session.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Session" }
              examples:
                active:
                  summary: "An active session: reconnect"
                  value:
                    id: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                    object: session
                    livemode: true
                    status: active
                    check: chk_n7p4r6s9t0wxyhk5zba2q8v1m3
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent:
                      - tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXNlc3Npb24rand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwMzAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwic3ViIjoiYWNjdF83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRscCI6eyJjaGVjayI6ImNoa19uN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtMyIsImV1IjoiM2Y5YzFhN2U1YjJkOGY0MDYxYzNlOWE3YjVkMmY4MDE2ZTRjOWEzYjdkMWY1ZTJjOGE2YjRkMGY5ZTNjN2ExNSIsImZhY2V0cyI6WyJmY3RfdjFtM243cDRyNnM5dDB3eHloazV6YmEycTgiXSwibGljZW5zZXMiOlt7ImxpY2Vuc2UiOiJsaWNfYmEycTh2MW0zbjdwNHI2czl0MHd4eWhrNXoiLCJyZXZpc2lvbiI6Imxydl83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRhbGVudCI6InRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyIsInRlcm1zX2RpZ2VzdCI6InNoYTI1Njo4ZTBhMmM0ZTZiOGQwZjJhNGM2ZThiMGQyZjRhNmM4ZTBiMmQ0ZjZhOGMwZTJiNGQ2ZjhhMGMyZTRiNmQ4ZjBhIn1dLCJzYW1wbGluZyI6eyJhdWRpb193aW5kb3dfbWF4IjoiUFQxNVMiLCJ0cmFuc2NyaXB0IjoiZXZlcnlfdHVybiJ9LCJzZXNzaW9uIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwidGFsZW50IjpbInRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyJdLCJ1c2UiOnsiY2hhbm5lbHMiOlsiaW5fYXBwIl0sImNvbW1lcmNpYWwiOmZhbHNlLCJraW5kIjoiaW1wZXJzb25hdGlvbiIsIm1vZGFsaXR5Ijoic3BlZWNoIiwicHVycG9zZSI6InBlcnNvbmFsIiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.RD_dRcXCqGHhYvg-PV3b1JIAoAX-WzVp02x6j-eSzmhYFxuZvniuJVrhJuHmzlFq_FYr6smqYXHQzb5p8DI0gA
                    expires_at: "2026-10-17T18:05:00Z"
                    renew_every: PT60S
                    sampling:
                      audio_window_max: PT15S
                      transcript: every_turn
                    obligations:
                      - type: disclosure
                        level: licensed
                        placement: visible
                        text: AI voice of Maya Okafor, licensed.
                      - type: generation_instructions
                        instructions:
                          - Do not discuss politics or religion.
                          - Do not make promises on her behalf.
                        term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                      - type: usage_report
                        units: seconds
                        within: P1D
                    reasons: []
                    stream_url: wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream
                    termination: null
                    ended_at: null
                    metadata: {}
                    created_at: "2026-10-17T18:00:00Z"
                terminated:
                  summary: "A session Reflections terminated: stop output"
                  value:
                    id: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                    object: session
                    livemode: true
                    status: terminated
                    check: chk_n7p4r6s9t0wxyhk5zba2q8v1m3
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent:
                      - tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    token: null
                    expires_at: null
                    renew_every: PT60S
                    sampling:
                      audio_window_max: PT15S
                      transcript: every_turn
                    obligations:
                      - type: disclosure
                        level: licensed
                        placement: visible
                        text: AI voice of Maya Okafor, licensed.
                      - type: generation_instructions
                        instructions:
                          - Do not discuss politics or religion.
                          - Do not make promises on her behalf.
                        term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                      - type: usage_report
                        units: seconds
                        within: P1D
                    reasons: []
                    stream_url: wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream
                    termination:
                      reason: license_revoked
                      sentence: Maya Okafor revoked this license.
                      revocation: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                      sample: null
                      at: "2026-10-17T18:03:41Z"
                    ended_at: null
                    metadata: {}
                    created_at: "2026-10-17T18:00:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /sessions/{session_id}/renew:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: renewSession
      summary: Renew a session
      x-mint:
        href: /api-reference/sessions/renew-a-session
        metadata:
          playground: simple
      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).

        Returns a fresh session token. Renew every `renew_every` (60 seconds). Renewal fails with
        `session_not_active` once the license is revoked, suspended or ends, or the session was
        terminated; stop output at once when it fails.

        Restricted keys need `sessions:write`.
      tags: [Sessions]
      security:
        - { SecretKey: [sessions:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/SessionId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The renewed token.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/SessionRenewal" }
              examples:
                renewed:
                  summary: A renewed session token
                  value:
                    token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXNlc3Npb24rand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwMzAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwic3ViIjoiYWNjdF83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRscCI6eyJjaGVjayI6ImNoa19uN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtMyIsImV1IjoiM2Y5YzFhN2U1YjJkOGY0MDYxYzNlOWE3YjVkMmY4MDE2ZTRjOWEzYjdkMWY1ZTJjOGE2YjRkMGY5ZTNjN2ExNSIsImZhY2V0cyI6WyJmY3RfdjFtM243cDRyNnM5dDB3eHloazV6YmEycTgiXSwibGljZW5zZXMiOlt7ImxpY2Vuc2UiOiJsaWNfYmEycTh2MW0zbjdwNHI2czl0MHd4eWhrNXoiLCJyZXZpc2lvbiI6Imxydl83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRhbGVudCI6InRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyIsInRlcm1zX2RpZ2VzdCI6InNoYTI1Njo4ZTBhMmM0ZTZiOGQwZjJhNGM2ZThiMGQyZjRhNmM4ZTBiMmQ0ZjZhOGMwZTJiNGQ2ZjhhMGMyZTRiNmQ4ZjBhIn1dLCJzYW1wbGluZyI6eyJhdWRpb193aW5kb3dfbWF4IjoiUFQxNVMiLCJ0cmFuc2NyaXB0IjoiZXZlcnlfdHVybiJ9LCJzZXNzaW9uIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwidGFsZW50IjpbInRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyJdLCJ1c2UiOnsiY2hhbm5lbHMiOlsiaW5fYXBwIl0sImNvbW1lcmNpYWwiOmZhbHNlLCJraW5kIjoiaW1wZXJzb25hdGlvbiIsIm1vZGFsaXR5Ijoic3BlZWNoIiwicHVycG9zZSI6InBlcnNvbmFsIiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.RD_dRcXCqGHhYvg-PV3b1JIAoAX-WzVp02x6j-eSzmhYFxuZvniuJVrhJuHmzlFq_FYr6smqYXHQzb5p8DI0gA
                    expires_at: "2026-10-17T18:06:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY:?Set REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/renew' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/renew", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/renew",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_RENEW_SESSION_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/renew", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /sessions/{session_id}/samples:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createSessionSample
      summary: Submit a sample
      x-mint:
        href: /api-reference/sessions/submit-a-sample
        metadata:
          playground: simple
      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).

        Submits a sample of what the session produced: an audio window, a transcript turn or a video
        frame. Submit at least as often as `sampling` requires. A `deny` means stop output within
        one second and end the session; Reflections also terminates it.

        Restricted keys need `sessions:write`.
      tags: [Sessions]
      security:
        - { SecretKey: [sessions:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/SessionId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/SampleCreate" }
            examples:
              transcript:
                summary: The words of one turn
                value:
                  kind: transcript
                  window:
                    start_ms: 61200
                    end_ms: 64600
                  text: Great question. My favourite trail is the ridge loop above the lake.
      responses:
        "200":
          description: The sample, with its decision.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Sample" }
              examples:
                allowed:
                  summary: An allowed transcript sample
                  value:
                    id: smp_83h8zrxz7htd27m9ws77zr6r0b
                    object: session_sample
                    session: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                    kind: transcript
                    decision: allow
                    reasons: []
                    findings:
                      - term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                        rule: Do not discuss politics or religion.
                        result: preserved
                    created_at: "2026-10-17T18:01:05Z"
                denied:
                  summary: "A denied sample: stop output"
                  value:
                    id: smp_bn39vtsnc8vptth9q70zn0hvpg
                    object: session_sample
                    session: ses_kmfnmpba5q2z9nxajjxyy5drxj
                    kind: transcript
                    decision: deny
                    reasons:
                      - code: prohibited_custom_term
                        stage: session
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                        sentence: Do not discuss politics or religion.
                    findings:
                      - term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                        rule: Do not discuss politics or religion.
                        result: violated
                        detail: The turn tells the listener which candidate to vote for.
                    created_at: "2026-10-16T21:07:52Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/samples' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "kind": "transcript",
              "window": {
                "start_ms": 61200,
                "end_ms": 64600
              },
              "text": "Great question. My favourite trail is the ridge loop above the lake."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/samples", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "kind": "transcript",
                "window": {
                  "start_ms": 61200,
                  "end_ms": 64600
                },
                "text": "Great question. My favourite trail is the ridge loop above the lake."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "kind": "transcript",
                "window": {"start_ms": 61200, "end_ms": 64600},
                "text": "Great question. My favourite trail is the ridge loop above the lake.",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/samples",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_SESSION_SAMPLE_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "kind": "transcript",
                  "window": {
                    "start_ms": 61200,
                    "end_ms": 64600
                  },
                  "text": "Great question. My favourite trail is the ridge loop above the lake."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/samples", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /sessions/{session_id}/end:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: endSession
      summary: End a session
      x-mint:
        href: /api-reference/sessions/end-a-session
        metadata:
          playground: simple
      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).

        Ends a session. Report its usage with a usage record that names the session.

        Restricted keys need `sessions:write`.
      tags: [Sessions]
      security:
        - { SecretKey: [sessions:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/SessionId"
        - $ref: "#/components/parameters/IdempotencyKey"
      responses:
        "200":
          description: The ended session.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Session" }
              examples:
                ended:
                  summary: A session your user ended
                  value:
                    id: ses_rmg9dttrhnzvq421w3fkkjrad8
                    object: session
                    livemode: true
                    status: ended
                    check: chk_kasyaf3mrnpf7n133b4nme037s
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent:
                      - tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    token: null
                    expires_at: null
                    renew_every: PT60S
                    sampling:
                      audio_window_max: PT15S
                      transcript: every_turn
                    obligations:
                      - type: disclosure
                        level: licensed
                        placement: visible
                        text: AI voice of Maya Okafor, licensed.
                      - type: generation_instructions
                        instructions:
                          - Do not discuss politics or religion.
                          - Do not make promises on her behalf.
                        term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                      - type: usage_report
                        units: seconds
                        within: P1D
                    reasons: []
                    stream_url: wss://app.reflections.ai/v1/sessions/ses_rmg9dttrhnzvq421w3fkkjrad8/stream
                    termination: null
                    ended_at: "2026-10-16T20:27:36Z"
                    metadata: {}
                    created_at: "2026-10-16T20:15:00Z"
                terminated:
                  summary: A terminated session keeps its status
                  value:
                    id: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                    object: session
                    livemode: true
                    status: terminated
                    check: chk_n7p4r6s9t0wxyhk5zba2q8v1m3
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent:
                      - tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    token: null
                    expires_at: null
                    renew_every: PT60S
                    sampling:
                      audio_window_max: PT15S
                      transcript: every_turn
                    obligations:
                      - type: disclosure
                        level: licensed
                        placement: visible
                        text: AI voice of Maya Okafor, licensed.
                      - type: generation_instructions
                        instructions:
                          - Do not discuss politics or religion.
                          - Do not make promises on her behalf.
                        term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                      - type: usage_report
                        units: seconds
                        within: P1D
                    reasons: []
                    stream_url: wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream
                    termination:
                      reason: license_revoked
                      sentence: Maya Okafor revoked this license.
                      revocation: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                      sample: null
                      at: "2026-10-17T18:03:41Z"
                    ended_at: "2026-10-17T18:03:42Z"
                    metadata: {}
                    created_at: "2026-10-17T18:00:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY:?Set REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/end' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/end", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/end",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_END_SESSION_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/end", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /receipts/{receipt_id}:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveReceipt
      summary: Retrieve a receipt
      x-mint:
        href: /api-reference/receipts/retrieve-a-receipt
      description: |
        **Test mode available. Live mode available when configured.** Source support does not
        establish production activation or the existence of live receipts. Test and live receipts
        are public to anyone holding their ID. The live projection exposes signed claims and
        current use status, never prompt text, execution job IDs or private metadata. Receipts
        remain for seven years independently of the private detail and file retention windows.
        Test receipt verification still requires a test key.

        Returns a receipt and its live status. Anyone with the receipt ID may read it with any key,
        or with no key at the public rate limit. The signed `jws` can be verified offline against
        the keys at `/.well-known/jwks.json`; `use_status` says what use is permitted now.
      tags: [Receipts]
      security:
        - SecretKey: []
        - {}
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: receipt_id
          in: path
          required: true
          description: The receipt's ID, `rcpt_…`. Anyone who has it may read the receipt.
          example: rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
          schema: { type: string, pattern: "^rcpt_[0-9a-hjkmnp-tv-z]{26}$" }
      responses:
        "200":
          description: The receipt.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Receipt" }
              examples:
                receipt: { $ref: "#/components/examples/Receipt" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/receipts/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/receipts/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/receipts/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/receipts/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /verifications:
    post:
      x-reflections-availability: { test: available, live: available }
      operationId: createVerification
      summary: Verify content
      x-mint:
        href: /api-reference/verifications/verify-content
      description: |
        **Test mode available. Live mode available when configured.** Source support does not
        establish production activation. The initial live implementation accepts JSON with a
        receipt ID, receipt JWS or SHA-256. Receipt-ID and JWS verification are public; digest
        discovery requires the owning account's live key. The response exposes the signed receipt
        and current use status without private request metadata. Sandbox verification requires a
        test key. Multipart files, manifests, URLs and fingerprints are unsupported in both modes.
        Live verification creates a fresh verification ID on each call; it does not provide the
        exact response replay implemented for live check and generation creation.

        **Broader protocol contract:** the remaining description and examples include planned
        verification forms beyond those supported JSON inputs.

        Verifies a file, a C2PA manifest or a receipt, and returns the receipt it matches with its
        live status. A file is read for an embedded manifest first, then matched by its exact
        digest, then by fingerprint and watermark, so verification still works after metadata is
        stripped or the file is re-encoded. `method` says which one matched. Anyone may verify;
        without a key the public rate limit applies. Test-mode receipts verify only with a test
        key.
      tags: [Verifications]
      security:
        - SecretKey: []
        - {}
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/VerificationCreate" }
            examples:
              receipt:
                summary: A receipt ID, for its live status
                value:
                  receipt: rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
              fingerprint:
                summary: A fingerprint computed on your platform
                value:
                  fingerprint:
                    perceptual_hash:
                      algorithm: pdq
                      value: 37e9846ce3ba171f08bf527b156838dec7fd0cb2d474137d16f0b22f6b9dc144
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file:
                  type: string
                  format: binary
      responses:
        "200":
          description: The verification.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Verification" }
              examples:
                verification: { $ref: "#/components/examples/Verification" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "409": { $ref: "#/components/responses/Conflict" }
        "413": { $ref: "#/components/responses/PayloadTooLarge" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
        "504": { $ref: "#/components/responses/Timeout" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/verifications' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/verifications", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/verifications",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_VERIFICATION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "receipt": "rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/verifications", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /revocations:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createRevocation
      summary: Create a revocation
      x-mint:
        href: /api-reference/revocations/create-a-revocation
        metadata:
          playground: simple
      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).

        Revokes one license of a talent you represent. Needs a mandate with `revoke` for the
        talent. It takes effect when this call returns: new checks deny, pending and held work
        under the license is void, live sessions end within seconds, and every platform that used
        it must act by `acknowledge_by`, 24 hours later. A revocation cannot be undone; to pause a
        license instead, [suspend it](/api-reference/licenses/suspend-a-license).

        Set `for_cause` only for a breach, with the `cause` the platforms will read. Only a
        revocation for cause applies a license's `withdraw` policy to released outputs, which
        platforms must take down and acknowledge by `post_revocation.withdraw_by`.

        Only the talent withdraws a facet, withdraws consent everywhere or ends a mandate, in the
        Talent Portal. Those revocations reach you in the feed and as `revocation.created`.

        Restricted keys need `revocations:write`.
      tags: [Revocations]
      security:
        - { SecretKey: [revocations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/RevocationCreate" }
            examples:
              by_representative:
                summary: Revoke a license as a representative
                value:
                  license: lic_31x87g772xdcz1n1za29601rbt
                  note: The campaign ended early.
      responses:
        "200":
          description: The revocation, in effect.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Revocation" }
              examples:
                by_representative: { $ref: "#/components/examples/RevocationByRepresentative" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/revocations' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "license": "lic_31x87g772xdcz1n1za29601rbt",
              "note": "The campaign ended early."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/revocations", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "license": "lic_31x87g772xdcz1n1za29601rbt",
                "note": "The campaign ended early."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"license": "lic_31x87g772xdcz1n1za29601rbt", "note": "The campaign ended early."}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/revocations",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_REVOCATION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "license": "lic_31x87g772xdcz1n1za29601rbt",
                  "note": "The campaign ended early."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/revocations", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: listRevocations
      summary: List revocations
      x-mint:
        href: /api-reference/revocations/list-revocations
      description: |
        **Test mode available. Live mode unavailable.** The sandbox feed is always empty. Creating and applying revocations is not implemented.

        The revocation feed. Pass `after` with the last revocation ID you processed to read
        everything since, oldest first. Platforms that cache decisions must read this feed at least
        every 60 seconds; webhooks are the fast path, this is the source of truth. A
        representative sees the revocations of every talent it represents, with each platform's
        acknowledgements.

        Restricted keys need `revocations:write`.
      tags: [Revocations]
      security:
        - { SecretKey: [revocations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: talent
          in: query
          description: Only revocations whose `targets.talent` is this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: after
          in: query
          description: Return revocations created after this one, oldest first.
          schema: { type: string, pattern: "^rvk_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: |
            Only revocations with this status. `pending_acknowledgement` and `overdue` list the ones
            that still need acknowledging.
          schema: { $ref: "#/components/schemas/RevocationStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of revocations.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/RevocationList" }
              examples:
                feed_after_cursor:
                  summary: The feed after a cursor, oldest first
                  value:
                    object: list
                    data:
                      - id: rvk_6z4ke43tnnk4h14drgv1tt82q1
                        object: revocation
                        livemode: true
                        scope: license
                        targets:
                          talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                          licenses:
                            - lic_zfjz8gb26kcd5ynj2tpb55e8bp
                          facets: []
                          mandate: null
                        status: overdue
                        initiated_by: talent
                        for_cause: true
                        cause: Outputs used outside the licensed territories.
                        note: null
                        effective_at: "2026-10-02T15:20:00Z"
                        post_revocation:
                          policy: withdraw
                          withdraw_by: "2026-10-09T15:20:00Z"
                        required_actions:
                          - stop_generation
                          - purge_cached_decisions
                          - withdraw_outputs
                        provider_copies: []
                        affected:
                          checks_denied: 0
                          generations_denied: 1
                          sessions_terminated: 0
                          released_outputs: 14
                        acknowledge_by: "2026-10-03T15:20:00Z"
                        acknowledgements:
                          - account: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                            actions:
                              - stop_generation
                              - purge_cached_decisions
                            deleted_copies: []
                            note: Generation stopped and caches purged. Takedowns are in progress.
                            acknowledged_at: "2026-10-02T15:34:51Z"
                        created_at: "2026-10-02T15:20:00Z"
                      - id: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                        object: revocation
                        livemode: true
                        scope: license
                        targets:
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          licenses:
                            - lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                          facets:
                            - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                          mandate: null
                        status: pending_acknowledgement
                        initiated_by: talent
                        for_cause: false
                        cause: null
                        note: null
                        effective_at: "2026-10-17T18:03:40Z"
                        post_revocation:
                          policy: retain
                          withdraw_by: null
                        required_actions:
                          - stop_generation
                          - purge_cached_decisions
                          - delete_provider_copies
                        provider_copies:
                          - facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                            provider: example-voice-provider
                            external_id: vx_4f9a2c
                        affected:
                          checks_denied: 3
                          generations_denied: 0
                          sessions_terminated: 1
                          released_outputs: 418
                        acknowledge_by: "2026-10-18T18:03:40Z"
                        acknowledgements: []
                        created_at: "2026-10-17T18:03:40Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/revocations?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/revocations?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/revocations?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/revocations?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /revocations/{revocation_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveRevocation
      summary: Retrieve a revocation
      x-mint:
        href: /api-reference/revocations/retrieve-a-revocation
        metadata:
          playground: simple
      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).

        Returns a revocation: what it cut, the actions it requires, its deadlines, and every
        acknowledgement received so far. A representative can retrieve the revocations of every
        talent it represents.

        Restricted keys need `revocations:write`.
      tags: [Revocations]
      security:
        - { SecretKey: [revocations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/RevocationId"
      responses:
        "200":
          description: The revocation.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Revocation" }
              examples:
                revocation: { $ref: "#/components/examples/Revocation" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /revocations/{revocation_id}/acknowledgements:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createRevocationAcknowledgement
      summary: Acknowledge a revocation
      x-mint:
        href: /api-reference/revocations/acknowledge-a-revocation
        metadata:
          playground: simple
      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).

        Attests that your platform has done what the revocation requires: stopped generating,
        purged cached decisions, deleted copies held at providers, and applied `post_revocation`
        to released outputs. Acknowledge every action but `withdraw_outputs` before
        `acknowledge_by`, and `withdraw_outputs` before `post_revocation.withdraw_by`; you may
        call this more than once. Acknowledgements are shown on the talent's record.

        Restricted keys need `revocations:write`.
      tags: [Revocations]
      security:
        - { SecretKey: [revocations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/RevocationId"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/AcknowledgementCreate" }
            examples:
              deleted_copies:
                summary: Actions done, with the deleted voice
                value:
                  actions:
                    - stop_generation
                    - purge_cached_decisions
                    - delete_provider_copies
                  deleted_copies:
                    - provider: example-voice-provider
                      external_id: vx_4f9a2c
                      deleted_at: "2026-10-17T18:09:12Z"
                  note: Voice deleted at the provider. Reuse caches purged.
      responses:
        "200":
          description: The revocation, with your acknowledgement.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Revocation" }
              examples:
                acknowledged:
                  summary: Every required action acknowledged
                  value:
                    id: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                    object: revocation
                    livemode: true
                    scope: license
                    targets:
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licenses:
                        - lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                      facets:
                        - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                      mandate: null
                    status: acknowledged
                    initiated_by: talent
                    for_cause: false
                    cause: null
                    note: null
                    effective_at: "2026-10-17T18:03:40Z"
                    post_revocation:
                      policy: retain
                      withdraw_by: null
                    required_actions:
                      - stop_generation
                      - purge_cached_decisions
                      - delete_provider_copies
                    provider_copies:
                      - facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                        provider: example-voice-provider
                        external_id: vx_4f9a2c
                    affected:
                      checks_denied: 3
                      generations_denied: 0
                      sessions_terminated: 1
                      released_outputs: 418
                    acknowledge_by: "2026-10-18T18:03:40Z"
                    acknowledgements:
                      - account: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        actions:
                          - stop_generation
                          - purge_cached_decisions
                          - delete_provider_copies
                        deleted_copies:
                          - provider: example-voice-provider
                            external_id: vx_4f9a2c
                            deleted_at: "2026-10-17T18:09:12Z"
                        note: Voice deleted at the provider. Reuse caches purged.
                        acknowledged_at: "2026-10-17T18:09:31Z"
                    created_at: "2026-10-17T18:03:40Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6/acknowledgements' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "actions": [
                "stop_generation",
                "purge_cached_decisions",
                "delete_provider_copies"
              ],
              "deleted_copies": [
                {
                  "provider": "example-voice-provider",
                  "external_id": "vx_4f9a2c",
                  "deleted_at": "2026-10-17T18:09:12Z"
                }
              ],
              "note": "Voice deleted at the provider. Reuse caches purged."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6/acknowledgements", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "actions": [
                  "stop_generation",
                  "purge_cached_decisions",
                  "delete_provider_copies"
                ],
                "deleted_copies": [
                  {
                    "provider": "example-voice-provider",
                    "external_id": "vx_4f9a2c",
                    "deleted_at": "2026-10-17T18:09:12Z"
                  }
                ],
                "note": "Voice deleted at the provider. Reuse caches purged."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "actions": ["stop_generation", "purge_cached_decisions", "delete_provider_copies"],
                "deleted_copies": [
                    {
                        "provider": "example-voice-provider",
                        "external_id": "vx_4f9a2c",
                        "deleted_at": "2026-10-17T18:09:12Z",
                    },
                ],
                "note": "Voice deleted at the provider. Reuse caches purged.",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6/acknowledgements",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_REVOCATION_ACKNOWLEDGEMENT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "actions": [
                    "stop_generation",
                    "purge_cached_decisions",
                    "delete_provider_copies"
                  ],
                  "deleted_copies": [
                    {
                      "provider": "example-voice-provider",
                      "external_id": "vx_4f9a2c",
                      "deleted_at": "2026-10-17T18:09:12Z"
                    }
                  ],
                  "note": "Voice deleted at the provider. Reuse caches purged."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/revocations/rvk_s9t0wxyhk5zba2q8v1m3n7p4r6/acknowledgements", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /usage_records:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createUsageRecords
      summary: Report usage
      x-mint:
        href: /api-reference/usage-records/report-usage
        metadata:
          playground: simple
      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).

        Reports usage for up to 1,000 generations or sessions in one call. Each record names what it
        settles. Records are reconciled against Reflections' own record of checks and generations;
        a record that names an unknown subject or exceeds what was observed is rejected with a
        reason. Send corrections as new records with `correction_of`.

        Restricted keys need `usage:write`.
      tags: [Usage records]
      security:
        - { SecretKey: [usage:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/UsageRecordBatchCreate" }
            examples:
              seconds_batch:
                summary: A session and a voice line, in seconds
                value:
                  records:
                    - subject: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                      units: seconds
                      quantity: 412
                      occurred_at: "2026-10-17T18:07:00Z"
                    - subject: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
                      units: seconds
                      quantity: 3.4
                      occurred_at: "2026-10-17T18:06:03Z"
      responses:
        "200":
          description: The created records, accepted or rejected one by one.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/UsageRecordList" }
              examples:
                one_rejected:
                  summary: One record accepted, one rejected
                  value:
                    object: list
                    data:
                      - id: ur_6a8c0e2g4j6m8p0r2t4w6y8b0d
                        object: usage_record
                        livemode: true
                        subject: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                        units: seconds
                        quantity: 412
                        occurred_at: "2026-10-17T18:07:00Z"
                        status: accepted
                        rejection: null
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        statement: stmt_3d5f7h9k1m3p5r7t9w1y3a5c7e
                        created_at: "2026-10-17T19:00:04Z"
                      - id: ur_8c0e2g4j6m8p0r2t4w6y8b0d2f
                        object: usage_record
                        livemode: true
                        subject: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
                        units: seconds
                        quantity: 3.4
                        occurred_at: "2026-10-17T18:06:03Z"
                        status: rejected
                        rejection:
                          code: duplicate
                          detail: ur_4y6a8c0e2g4j6m8p0r2t4w6y8b already reports this generation in seconds.
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        statement: null
                        created_at: "2026-10-17T19:00:04Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/usage_records' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "records": [
                {
                  "subject": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
                  "units": "seconds",
                  "quantity": 412,
                  "occurred_at": "2026-10-17T18:07:00Z"
                },
                {
                  "subject": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
                  "units": "seconds",
                  "quantity": 3.4,
                  "occurred_at": "2026-10-17T18:06:03Z"
                }
              ]
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/usage_records", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "records": [
                  {
                    "subject": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
                    "units": "seconds",
                    "quantity": 412,
                    "occurred_at": "2026-10-17T18:07:00Z"
                  },
                  {
                    "subject": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
                    "units": "seconds",
                    "quantity": 3.4,
                    "occurred_at": "2026-10-17T18:06:03Z"
                  }
                ]
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "records": [
                    {
                        "subject": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
                        "units": "seconds",
                        "quantity": 412,
                        "occurred_at": "2026-10-17T18:07:00Z",
                    },
                    {
                        "subject": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
                        "units": "seconds",
                        "quantity": 3.4,
                        "occurred_at": "2026-10-17T18:06:03Z",
                    },
                ],
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/usage_records",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_USAGE_RECORDS_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "records": [
                    {
                      "subject": "ses_q8v1m3n7p4r6s9t0wxyhk5zba2",
                      "units": "seconds",
                      "quantity": 412,
                      "occurred_at": "2026-10-17T18:07:00Z"
                    },
                    {
                      "subject": "gen_2q8v1m3n7p4r6s9t0wxyhk5zba",
                      "units": "seconds",
                      "quantity": 3.4,
                      "occurred_at": "2026-10-17T18:06:03Z"
                    }
                  ]
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/usage_records", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listUsageRecords
      summary: List usage records
      x-mint:
        href: /api-reference/usage-records/list-usage-records
        metadata:
          playground: simple
      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).

        Lists the usage records you reported. A representative whose mandate has
        `receive_statements` sees every usage record under the talent's licenses.

        Restricted keys need `usage:write` or `usage:read`.
      tags: [Usage records]
      security:
        - { SecretKey: [usage:write] }
        - { SecretKey: [usage:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: talent
          in: query
          description: Only records under this talent's licenses.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: license
          in: query
          description: Only records that count against this license.
          schema: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: Only `accepted` or only `rejected` records.
          schema: { type: string, enum: [accepted, rejected] }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of usage records.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/UsageRecordList" }
              examples:
                one_license:
                  summary: Usage records for one license
                  value:
                    object: list
                    data:
                      - id: ur_8c0e2g4j6m8p0r2t4w6y8b0d2f
                        object: usage_record
                        livemode: true
                        subject: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
                        units: seconds
                        quantity: 3.4
                        occurred_at: "2026-10-17T18:06:03Z"
                        status: rejected
                        rejection:
                          code: duplicate
                          detail: ur_4y6a8c0e2g4j6m8p0r2t4w6y8b already reports this generation in seconds.
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        statement: null
                        created_at: "2026-10-17T19:00:04Z"
                      - id: ur_6a8c0e2g4j6m8p0r2t4w6y8b0d
                        object: usage_record
                        livemode: true
                        subject: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                        units: seconds
                        quantity: 412
                        occurred_at: "2026-10-17T18:07:00Z"
                        status: accepted
                        rejection: null
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        statement: stmt_3d5f7h9k1m3p5r7t9w1y3a5c7e
                        created_at: "2026-10-17T19:00:04Z"
                      - id: ur_4y6a8c0e2g4j6m8p0r2t4w6y8b
                        object: usage_record
                        livemode: true
                        subject: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
                        units: seconds
                        quantity: 3.4
                        occurred_at: "2026-10-17T18:06:03Z"
                        status: accepted
                        rejection: null
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        statement: stmt_3d5f7h9k1m3p5r7t9w1y3a5c7e
                        created_at: "2026-10-17T18:06:30Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/usage_records?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/usage_records?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/usage_records?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/usage_records?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /statements:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listStatements
      summary: List statements
      x-mint:
        href: /api-reference/statements/list-statements
        metadata:
          playground: simple
      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).

        Lists statements for licenses you hold. A representative whose mandate has
        `receive_statements` sees the talent's statements.

        Restricted keys need `statements:read`.
      tags: [Statements]
      security:
        - { SecretKey: [statements:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: talent
          in: query
          description: Only statements for this talent's licenses.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: license
          in: query
          description: Only statements for this license.
          schema: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: Only statements with this status, such as `issued`.
          schema: { $ref: "#/components/schemas/StatementStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of statements.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/StatementList" }
              examples:
                one_license:
                  summary: An open month and a paid month
                  value:
                    object: list
                    data:
                      - id: stmt_3d5f7h9k1m3p5r7t9w1y3a5c7e
                        object: statement
                        livemode: true
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        status: open
                        period:
                          start: "2026-10-01T00:00:00Z"
                          end: "2026-11-01T00:00:00Z"
                        currency: usd
                        lines:
                          - description: Speech in Maya Okafor's voice
                            units: seconds
                            reported: 18240
                            observed: 18262
                            billable: 18262
                            rate:
                              amount: 2
                              currency: usd
                            amount: 36524
                        amount_due: 36524
                        amount_paid: 0
                        reconciliation:
                          result: under_reported
                          detail: 22 seconds observed in generations with no usage record.
                        payments: []
                        due_at: null
                        issued_at: null
                        document_url: null
                        created_at: "2026-10-01T00:00:00Z"
                      - id: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                        object: statement
                        livemode: true
                        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        status: paid
                        period:
                          start: "2026-09-01T00:00:00Z"
                          end: "2026-10-01T00:00:00Z"
                        currency: usd
                        lines:
                          - description: Speech in Maya Okafor's voice
                            units: seconds
                            reported: 41236
                            observed: 41236
                            billable: 41236
                            rate:
                              amount: 2
                              currency: usd
                            amount: 82472
                        amount_due: 82472
                        amount_paid: 82472
                        reconciliation:
                          result: matched
                          detail: null
                        payments:
                          - id: pay_sa9z70h0p3p3npjcjv3gfn3330
                            amount: 82472
                            paid_at: "2026-10-14T16:30:00Z"
                            method: bank_transfer
                            reference: WIRE-58214
                            confirmed_at: "2026-10-16T09:00:00Z"
                        due_at: "2026-10-31T00:00:00Z"
                        issued_at: "2026-10-08T08:00:00Z"
                        document_url: https://app.reflections.ai/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                        created_at: "2026-09-01T00:00:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/statements?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/statements?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/statements?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/statements?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /statements/{statement_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveStatement
      summary: Retrieve a statement
      x-mint:
        href: /api-reference/statements/retrieve-a-statement
        metadata:
          playground: simple
      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).

        Returns a statement: each line's reported, observed and billable units, the amounts, the
        reconciliation result and the recorded payments. A representative whose mandate has
        `receive_statements` can retrieve the talent's statements.

        Restricted keys need `statements:read`.
      tags: [Statements]
      security:
        - { SecretKey: [statements:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/StatementId"
      responses:
        "200":
          description: The statement.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Statement" }
              examples:
                statement: { $ref: "#/components/examples/Statement" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /statements/{statement_id}/payments:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createStatementPayment
      summary: Record a payment
      x-mint:
        href: /api-reference/statements/record-a-payment
        metadata:
          playground: simple
      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).

        Records that the licensee paid the talent's payee against a statement. Reflections does not
        move money; this records the payment so both sides see the same balance. The talent's side
        confirms receipt in the Talent Portal or with
        [Confirm a payment](/api-reference/statements/confirm-a-payment).

        Restricted keys need `statements:write`.
      tags: [Statements]
      security:
        - { SecretKey: [statements:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/StatementId"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/PaymentCreate" }
            examples:
              bank_transfer:
                summary: A bank transfer for the amount due
                value:
                  amount: 82472
                  currency: usd
                  paid_at: "2026-10-14T16:30:00Z"
                  method: bank_transfer
                  reference: WIRE-58214
      responses:
        "200":
          description: The statement, with the payment.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Statement" }
              examples:
                payment_recorded:
                  summary: The payment, not yet confirmed
                  value:
                    id: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                    object: statement
                    livemode: true
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    status: issued
                    period:
                      start: "2026-09-01T00:00:00Z"
                      end: "2026-10-01T00:00:00Z"
                    currency: usd
                    lines:
                      - description: Speech in Maya Okafor's voice
                        units: seconds
                        reported: 41236
                        observed: 41236
                        billable: 41236
                        rate:
                          amount: 2
                          currency: usd
                        amount: 82472
                    amount_due: 82472
                    amount_paid: 82472
                    reconciliation:
                      result: matched
                      detail: null
                    payments:
                      - id: pay_sa9z70h0p3p3npjcjv3gfn3330
                        amount: 82472
                        paid_at: "2026-10-14T16:30:00Z"
                        method: bank_transfer
                        reference: WIRE-58214
                        confirmed_at: null
                    due_at: "2026-10-31T00:00:00Z"
                    issued_at: "2026-10-08T08:00:00Z"
                    document_url: https://app.reflections.ai/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                    created_at: "2026-09-01T00:00:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "amount": 82472,
              "currency": "usd",
              "paid_at": "2026-10-14T16:30:00Z",
              "method": "bank_transfer",
              "reference": "WIRE-58214"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "amount": 82472,
                "currency": "usd",
                "paid_at": "2026-10-14T16:30:00Z",
                "method": "bank_transfer",
                "reference": "WIRE-58214"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "amount": 82472,
                "currency": "usd",
                "paid_at": "2026-10-14T16:30:00Z",
                "method": "bank_transfer",
                "reference": "WIRE-58214",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "amount": 82472,
                  "currency": "usd",
                  "paid_at": "2026-10-14T16:30:00Z",
                  "method": "bank_transfer",
                  "reference": "WIRE-58214"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /statements/{statement_id}/payments/{payment_id}/confirm:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: confirmStatementPayment
      summary: Confirm a payment
      x-mint:
        href: /api-reference/statements/confirm-a-payment
        metadata:
          playground: simple
      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).

        Confirms that a payment the licensee recorded arrived. Needs a mandate with
        `receive_statements` for the talent. The statement becomes `paid` when confirmed payments
        reach `amount_due`. Confirming a payment twice returns the statement unchanged.

        Restricted keys need `statements:write`.
      tags: [Statements]
      security:
        - { SecretKey: [statements:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/StatementId"
        - $ref: "#/components/parameters/PaymentId"
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/PaymentConfirm" }
            examples:
              received:
                summary: The day the payment arrived
                value:
                  received_at: "2026-10-16T09:00:00Z"
      responses:
        "200":
          description: The statement, with the payment confirmed.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Statement" }
              examples:
                paid:
                  summary: Confirmed payments reach amount_due
                  value:
                    id: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                    object: statement
                    livemode: true
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    status: paid
                    period:
                      start: "2026-09-01T00:00:00Z"
                      end: "2026-10-01T00:00:00Z"
                    currency: usd
                    lines:
                      - description: Speech in Maya Okafor's voice
                        units: seconds
                        reported: 41236
                        observed: 41236
                        billable: 41236
                        rate:
                          amount: 2
                          currency: usd
                        amount: 82472
                    amount_due: 82472
                    amount_paid: 82472
                    reconciliation:
                      result: matched
                      detail: null
                    payments:
                      - id: pay_sa9z70h0p3p3npjcjv3gfn3330
                        amount: 82472
                        paid_at: "2026-10-14T16:30:00Z"
                        method: bank_transfer
                        reference: WIRE-58214
                        confirmed_at: "2026-10-16T09:00:00Z"
                    due_at: "2026-10-31T00:00:00Z"
                    issued_at: "2026-10-08T08:00:00Z"
                    document_url: https://app.reflections.ai/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                    created_at: "2026-09-01T00:00:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY:?Set REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments/pay_sa9z70h0p3p3npjcjv3gfn3330/confirm' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "received_at": "2026-10-16T09:00:00Z"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments/pay_sa9z70h0p3p3npjcjv3gfn3330/confirm", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "received_at": "2026-10-16T09:00:00Z"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"received_at": "2026-10-16T09:00:00Z"}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments/pay_sa9z70h0p3p3npjcjv3gfn3330/confirm",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CONFIRM_STATEMENT_PAYMENT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "received_at": "2026-10-16T09:00:00Z"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/payments/pay_sa9z70h0p3p3npjcjv3gfn3330/confirm", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /statements/{statement_id}/dispute:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: disputeStatement
      summary: Dispute a statement
      x-mint:
        href: /api-reference/statements/dispute-a-statement
        metadata:
          playground: simple
      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).

        Marks an issued statement `disputed`, with the reason the licensee will read. Needs a
        mandate with `receive_statements`. The licensee receives `statement.disputed`. Settle it
        with the licensee: when its usage records or payments change, Reflections reissues the
        statement and sends `statement.issued` again.

        Restricted keys need `statements:write`.
      tags: [Statements]
      security:
        - { SecretKey: [statements:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/StatementId"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/StatementDispute" }
            examples:
              unreported_usage:
                summary: Usage observed but not reported
                value:
                  reason: 36 seconds of September speech have no usage record. Report them so the statement reconciles.
      responses:
        "200":
          description: The disputed statement.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Statement" }
              examples:
                disputed:
                  summary: The statement, disputed
                  value:
                    id: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                    object: statement
                    livemode: true
                    license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    status: disputed
                    period:
                      start: "2026-09-01T00:00:00Z"
                      end: "2026-10-01T00:00:00Z"
                    currency: usd
                    lines:
                      - description: Speech in Maya Okafor's voice
                        units: seconds
                        reported: 41200
                        observed: 41236
                        billable: 41236
                        rate:
                          amount: 2
                          currency: usd
                        amount: 82472
                    amount_due: 82472
                    amount_paid: 0
                    reconciliation:
                      result: under_reported
                      detail: 36 seconds observed in generations with no usage record.
                    payments: []
                    due_at: "2026-10-31T00:00:00Z"
                    issued_at: "2026-10-02T08:00:00Z"
                    document_url: https://app.reflections.ai/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                    created_at: "2026-09-01T00:00:00Z"
                    dispute:
                      reason: 36 seconds of September speech have no usage record. Report them so the statement reconciles.
                      disputed_at: "2026-10-05T14:22:10Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY:?Set REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/dispute' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "reason": "36 seconds of September speech have no usage record. Report them so the statement reconciles."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/dispute", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "reason": "36 seconds of September speech have no usage record. Report them so the statement reconciles."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "reason": "36 seconds of September speech have no usage record. Report them so the statement reconciles.",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/dispute",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_DISPUTE_STATEMENT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "reason": "36 seconds of September speech have no usage record. Report them so the statement reconciles."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q/dispute", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /mandates:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listMandates
      summary: List mandates
      x-mint:
        href: /api-reference/mandates/list-mandates
        metadata:
          playground: simple
      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).

        Lists the mandates your account holds: each talent you represent, your role, and the powers
        the talent gave you. A talent appoints a representative in the Talent Portal; no endpoint
        creates a mandate. Every talent-side endpoint checks the mandate for the talent it acts on.

        Restricted keys need `mandates:read`.
      tags: [Mandates]
      security:
        - { SecretKey: [mandates:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: talent
          in: query
          description: Only the mandate for this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: Only mandates with this status.
          schema: { type: string, enum: [active, ended] }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of mandates.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/MandateList" }
              examples:
                active:
                  summary: A manager's active mandates
                  value:
                    object: list
                    data:
                      - id: mnd_ww2cs3e4j5tgqqxs7mt7746q4p
                        object: mandate
                        livemode: true
                        talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                        talent_name: Jonah Reyes
                        representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                        role: manager
                        powers:
                          - issue_licenses
                          - review_outputs
                          - receive_statements
                        status: active
                        starts_at: "2026-10-05T15:20:00Z"
                        ends_at: null
                        ended_at: null
                        revocation: null
                        created_at: "2026-10-05T15:20:00Z"
                      - id: mnd_7nb1ef0wykcj3mkwaba3x20ez6
                        object: mandate
                        livemode: true
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        talent_name: Maya Okafor
                        representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                        role: manager
                        powers:
                          - issue_licenses
                          - review_outputs
                          - revoke
                          - receive_statements
                        status: active
                        starts_at: "2026-06-12T10:00:00Z"
                        ends_at: null
                        ended_at: null
                        revocation: null
                        created_at: "2026-06-12T10:00:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/mandates?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/mandates?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/mandates?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/mandates?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /mandates/{mandate_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveMandate
      summary: Retrieve a mandate
      x-mint:
        href: /api-reference/mandates/retrieve-a-mandate
        metadata:
          playground: simple
      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).

        Returns one mandate your account holds: the talent, your role and the powers they gave you.
        A mandate that ended stays readable, with `ended_at` and, when the talent ended it, the
        `revocation` that did.

        Restricted keys need `mandates:read`.
      tags: [Mandates]
      security:
        - { SecretKey: [mandates:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/MandateId"
      responses:
        "200":
          description: The mandate.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Mandate" }
              examples:
                mandate: { $ref: "#/components/examples/Mandate" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/mandates/mnd_7nb1ef0wykcj3mkwaba3x20ez6' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/mandates/mnd_7nb1ef0wykcj3mkwaba3x20ez6", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/mandates/mnd_7nb1ef0wykcj3mkwaba3x20ez6",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/mandates/mnd_7nb1ef0wykcj3mkwaba3x20ez6", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /escalations:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listEscalations
      summary: List escalations
      x-mint:
        href: /api-reference/escalations/list-escalations
        metadata:
          playground: simple
      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 review queue: escalated checks and held outputs that the talent's side decides, for
        every talent whose mandate gives you `review_outputs`. Pass `status=open` for the items
        waiting on you, oldest `expires_at` first. Escalations under platform licenses are reviewed
        by Reflections and do not appear here.

        Restricted keys need `escalations:write`.
      tags: [Escalations]
      security:
        - { SecretKey: [escalations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: talent
          in: query
          description: Only escalations for this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: |
            Only escalations with this status. `open` lists the items waiting on you, oldest
            `expires_at` first.
          schema: { type: string, enum: [open, allowed, denied, expired, cancelled] }
        - name: reason
          in: query
          description: Only escalations raised for this reason. `release_review` lists held outputs.
          schema: { type: string, enum: [judgment, unverifiable, evaluation_unavailable, release_review] }
        - name: license
          in: query
          description: Only escalations under this license.
          schema: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of escalations.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/EscalationList" }
              examples:
                held_outputs:
                  summary: Held outputs waiting for release
                  value:
                    object: list
                    data:
                      - id: esc_hk5zba2q8v1m3n7p4r6s9t0wxy
                        object: escalation
                        livemode: true
                        reason: release_review
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-24T18:00:12Z"
                        resolved_at: null
                        note: null
                        subject:
                          object: generation
                          id: gen_6s9t0wxyhk5zba2q8v1m3n7p4r
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        licensee_name: Ridgeline
                        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        platform_name: Northlight
                        use:
                          modality: image
                          kind: depiction
                          purpose: advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                        inputs:
                          - role: prompt
                            text: Maya Okafor holding our new trail shoe on a rocky ridge at sunrise
                          - role: reference
                            sha256: 5e0b7c2d9f4a1e6b3c8d0f2a4e6b8c0d2f4a6e8b0c2d4f6a8e0b2c4d6f8a0b2c
                            media_type: image/jpeg
                            url: https://files.reflections.ai/esc_hk5zba2q8v1m3n7p4r6s9t0wxy/inputs/1?expires=1792262700&signature=i4wRIMXgvdxqeGBa4WCRRBqTCFlu1VQFXABNACbjwUY
                        reasons: []
                        findings:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            attribute: identity.samePerson
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                            attribute: appearance.wardrobe
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            rule: Do not show alcohol or tobacco.
                            result: preserved
                        artifact:
                          sha256: 9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a
                          media_type: image/png
                          url: https://files.reflections.ai/esc_hk5zba2q8v1m3n7p4r6s9t0wxy/artifact?expires=1792262700&signature=l63aNVqWPu8FjVP3LV1CGjGXEWmx83-lpwiTA5r4V8I
                        request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                        review_url: https://app.reflections.ai/review/esc_hk5zba2q8v1m3n7p4r6s9t0wxy
                        decision: null
                        decided_by: null
                        created_at: "2026-10-17T18:00:12Z"
                      - id: esc_czjcwnr6p65hakf55easq1aqa6
                        object: escalation
                        livemode: true
                        reason: release_review
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-24T18:08:53Z"
                        resolved_at: null
                        note: null
                        subject:
                          object: generation
                          id: gen_estxjc1sw4d0fbyra0jfd7x184
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        licensee_name: Ridgeline
                        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        platform_name: Northlight
                        use:
                          modality: image
                          kind: depiction
                          purpose: advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                        inputs:
                          - role: prompt
                            text: Maya Okafor holding our new trail shoe on a rocky ridge at sunrise
                          - role: reference
                            sha256: 5e0b7c2d9f4a1e6b3c8d0f2a4e6b8c0d2f4a6e8b0c2d4f6a8e0b2c4d6f8a0b2c
                            media_type: image/jpeg
                            url: https://files.reflections.ai/esc_czjcwnr6p65hakf55easq1aqa6/inputs/1?expires=1792262700&signature=IlWsHoYkr9dxXtR-oVKqtnjny--ufP0G0Lm4Mfbmm7o
                        reasons: []
                        findings:
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                            attribute: identity.samePerson
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                            attribute: appearance.wardrobe
                            result: preserved
                          - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                            rule: Do not show alcohol or tobacco.
                            result: preserved
                        artifact:
                          sha256: 85ccdc0c8087515ce6685fb5a44f0ac2f6e628919fa9b9b0256611712e973342
                          media_type: image/png
                          url: https://files.reflections.ai/esc_czjcwnr6p65hakf55easq1aqa6/artifact?expires=1792262700&signature=iyg2YgE8I5U-hyhnpLZ1BMVeZt9gweB2kIPFRNRNoIE
                        request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                        review_url: https://app.reflections.ai/review/esc_czjcwnr6p65hakf55easq1aqa6
                        decision: null
                        decided_by: null
                        created_at: "2026-10-17T18:08:53Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/escalations?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/escalations?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/escalations?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/escalations?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /escalations/{escalation_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveEscalation
      summary: Retrieve an escalation
      x-mint:
        href: /api-reference/escalations/retrieve-an-escalation
        metadata:
          playground: simple
      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).

        Returns an escalation with everything a reviewer needs: the request as the platform sent it,
        the use, the licensee and platform, the term the question rests on, and, for a held output,
        the findings on its bytes and a link to view it. Inputs sent with
        `prompt_handling: "withheld"` show only their role and digest.

        Restricted keys need `escalations:write`.
      tags: [Escalations]
      security:
        - { SecretKey: [escalations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/EscalationId"
      responses:
        "200":
          description: The escalation.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/EscalationDetail" }
              examples:
                open: { $ref: "#/components/examples/EscalationOpen" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /escalations/{escalation_id}/resolve:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: resolveEscalation
      summary: Resolve an escalation
      x-mint:
        href: /api-reference/escalations/resolve-an-escalation
        metadata:
          playground: simple
      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).

        Allows or denies an escalated check, or releases or declines a held output, on a person's
        decision. When the escalation's `reviewer` is `talent`, needs a mandate with
        `review_outputs` for the talent. `decided_by` names that person, and the decision is
        recorded on the talent's audit record with your account. An allow covers exactly the request that was escalated,
        bound by its `request_digest`; for a held output, it releases those bytes and issues their
        receipt. The platform receives `check.resolved`, `generation.released` or
        `generation.denied`.

        When a check invokes several talent, each escalated talent's side decides their own
        escalation. The check resolves to `allow` only when every one allows, and to `deny` as
        soon as one denies or expires; `check.resolved` is sent then, and the other open
        escalations become `cancelled`.

        Do not resolve escalations with an automated rule. To answer a kind of request the same
        way every time, change the license, so the answer becomes a checked term that every check
        applies.

        Restricted keys need `escalations:write`.
      tags: [Escalations]
      security:
        - { SecretKey: [escalations:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/EscalationId"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/EscalationResolve" }
            examples:
              allow_check:
                summary: Allow an escalated check
                value:
                  decision: allow
                  note: Fine as long as the cups hold coffee.
                  decided_by:
                    name: Lena Brooks
              decline_held_output:
                summary: Decline a held output
                value:
                  decision: deny
                  note: Another brand's logo shows on her jacket.
                  decided_by:
                    name: Lena Brooks
      responses:
        "200":
          description: The resolved escalation.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/EscalationDetail" }
              examples:
                allowed: { $ref: "#/components/examples/EscalationAllowed" }
                declined:
                  summary: A held output declined by the talent's manager
                  value:
                    id: esc_czjcwnr6p65hakf55easq1aqa6
                    object: escalation
                    livemode: true
                    reason: release_review
                    reviewer: talent
                    status: denied
                    expires_at: "2026-10-24T18:08:53Z"
                    resolved_at: "2026-10-17T19:44:30Z"
                    note: Another brand's logo shows on her jacket.
                    subject:
                      object: generation
                      id: gen_estxjc1sw4d0fbyra0jfd7x184
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                    license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    licensee_name: Ridgeline
                    platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    platform_name: Northlight
                    use:
                      modality: image
                      kind: depiction
                      purpose: advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                        - CA
                    inputs:
                      - role: prompt
                        text: Maya Okafor holding our new trail shoe on a rocky ridge at sunrise
                      - role: reference
                        sha256: 5e0b7c2d9f4a1e6b3c8d0f2a4e6b8c0d2f4a6e8b0c2d4f6a8e0b2c4d6f8a0b2c
                        media_type: image/jpeg
                        url: https://files.reflections.ai/esc_czjcwnr6p65hakf55easq1aqa6/inputs/1?expires=1792267170&signature=7DI25dYadMimwXWoRAuqBrI_2Fy6zpBW7vDSvnwbqr0
                    reasons: []
                    findings:
                      - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                        attribute: identity.samePerson
                        result: preserved
                      - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                        attribute: appearance.wardrobe
                        result: preserved
                      - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                        rule: Do not show alcohol or tobacco.
                        result: preserved
                    artifact:
                      sha256: 85ccdc0c8087515ce6685fb5a44f0ac2f6e628919fa9b9b0256611712e973342
                      media_type: image/png
                      url: https://files.reflections.ai/esc_czjcwnr6p65hakf55easq1aqa6/artifact?expires=1792267170&signature=q1fpBpzR8R0ouCmOA8wxr0hf6OFOT2qyMWmi7qf_wOQ
                    request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                    review_url: null
                    decision: deny
                    decided_by:
                      party: representative
                      account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                      name: Lena Brooks
                    created_at: "2026-10-17T18:08:53Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY:?Set REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9/resolve' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "decision": "allow",
              "note": "Fine as long as the cups hold coffee.",
              "decided_by": {
                "name": "Lena Brooks"
              }
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9/resolve", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "decision": "allow",
                "note": "Fine as long as the cups hold coffee.",
                "decided_by": {
                  "name": "Lena Brooks"
                }
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "decision": "allow",
                "note": "Fine as long as the cups hold coffee.",
                "decided_by": {"name": "Lena Brooks"},
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9/resolve",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_RESOLVE_ESCALATION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "decision": "allow",
                  "note": "Fine as long as the cups hold coffee.",
                  "decided_by": {
                    "name": "Lena Brooks"
                  }
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/escalations/esc_t0wxyhk5zba2q8v1m3n7p4r6s9/resolve", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /license_drafts:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createLicenseDraft
      summary: Draft a license
      x-mint:
        href: /api-reference/license-drafts/draft-a-license
        metadata:
          playground: simple
      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).

        Prepares terms for the talent's side to sign: a new license, an answer to a license
        request, or an amendment or renewal of an existing license. Needs a mandate with
        `issue_licenses` for the talent.

        A draft grants nothing. A person signs it with a passkey at `signing_url`, in the Talent
        Portal: the talent, or a person at your account when `signer` is `representative`. The
        signer may change terms before signing. Signing creates the license or its new revision,
        and the licensee then accepts it on its hosted acceptance page. No endpoint signs or
        accepts a license.

        Restricted keys need `license_drafts:write`.
      tags: [License drafts]
      security:
        - { SecretKey: [license_drafts:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseDraftCreate" }
            examples:
              renewal:
                summary: Renew a license for a new window
                value:
                  talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                  kind: renew
                  license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                  scope:
                    window:
                      starts_at: "2027-04-01T00:00:00-04:00"
                      ends_at: "2027-09-30T00:00:00-04:00"
                      time_zone: America/New_York
                  signer: talent
                  note: Spring and summer 2027, on the same terms.
              answer_request:
                summary: Answer a license request with narrower terms
                value:
                  talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                  license_request: lrq_ykaa695mrd8c92h3ahg476m47n
                  scope:
                    channels:
                      - social
                      - web
                    territories:
                      - US
                    rules:
                      never:
                        - Do not show alcohol or tobacco.
                      always: []
                      brief: null
                    release_policy: per_output_review
                  signer: talent
                  note: Social and web in the US only, with every output reviewed.
      responses:
        "200":
          description: The draft, open for signature.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseDraft" }
              examples:
                renewal: { $ref: "#/components/examples/LicenseDraft" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/license_drafts' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
              "kind": "renew",
              "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
              "scope": {
                "window": {
                  "starts_at": "2027-04-01T00:00:00-04:00",
                  "ends_at": "2027-09-30T00:00:00-04:00",
                  "time_zone": "America/New_York"
                }
              },
              "signer": "talent",
              "note": "Spring and summer 2027, on the same terms."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_drafts", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                "kind": "renew",
                "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                "scope": {
                  "window": {
                    "starts_at": "2027-04-01T00:00:00-04:00",
                    "ends_at": "2027-09-30T00:00:00-04:00",
                    "time_zone": "America/New_York"
                  }
                },
                "signer": "talent",
                "note": "Spring and summer 2027, on the same terms."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                "kind": "renew",
                "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                "scope": {
                    "window": {
                        "starts_at": "2027-04-01T00:00:00-04:00",
                        "ends_at": "2027-09-30T00:00:00-04:00",
                        "time_zone": "America/New_York",
                    },
                },
                "signer": "talent",
                "note": "Spring and summer 2027, on the same terms.",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/license_drafts",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "talent": "tal_9t0wxyhk5zba2q8v1m3n7p4r6s",
                  "kind": "renew",
                  "license": "lic_k5zba2q8v1m3n7p4r6s9t0wxyh",
                  "scope": {
                    "window": {
                      "starts_at": "2027-04-01T00:00:00-04:00",
                      "ends_at": "2027-09-30T00:00:00-04:00",
                      "time_zone": "America/New_York"
                    }
                  },
                  "signer": "talent",
                  "note": "Spring and summer 2027, on the same terms."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/license_drafts", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listLicenseDrafts
      summary: List license drafts
      x-mint:
        href: /api-reference/license-drafts/list-license-drafts
        metadata:
          playground: simple
      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).

        Lists the license drafts your account prepared, newest first. Filter by `talent`, or by
        `status`: `open` lists the drafts still waiting for a signature.

        Restricted keys need `license_drafts:write`.
      tags: [License drafts]
      security:
        - { SecretKey: [license_drafts:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: talent
          in: query
          description: Only drafts for this talent.
          schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        - name: status
          in: query
          description: Only drafts with this status.
          schema: { $ref: "#/components/schemas/LicenseDraftStatus" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of drafts.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseDraftList" }
              examples:
                drafts:
                  summary: Drafts for one talent, newest first
                  value:
                    object: list
                    data:
                      - id: ldr_tw5hx5mq8q0j5wry9hp32ftj0p
                        object: license_draft
                        livemode: true
                        status: signed
                        kind: issue
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                        license_request: null
                        scope:
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          window:
                            starts_at: "2026-10-01T00:00:00-04:00"
                            ends_at: "2027-03-31T00:00:00-04:00"
                            time_zone: America/New_York
                          adjustments:
                            reframe: true
                            background_extension: true
                            lighting: true
                            text_overlay: true
                            body_and_age: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skin_retouch: false
                            endorsement: false
                          prohibited_changes:
                            - body_and_age
                            - expression
                            - hair
                            - pose
                            - skin_retouch
                            - endorsement
                          required_attributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          rules:
                            never:
                              - Do not show alcohol or tobacco.
                            always: []
                            brief: null
                          release_policy: per_output_review
                          escalation_window: P7D
                          final_deliverables: 24
                          sessions:
                            permitted: false
                          material_access: []
                          platforms:
                            mode: any_connected
                            accounts: []
                          sublicense: none
                          training: prohibited
                          disclosure: brand
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity:
                            exclusive: false
                            category: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: placements
                              rate:
                                amount: 25000
                                currency: usd
                              per: 1
                            minimum:
                              amount: 500000
                              currency: usd
                            schedule: monthly
                        terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                        signer: talent
                        signing_url: null
                        signed_as_drafted: true
                        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                        decision_note: null
                        note: Social and Ridgeline's own website only. TV needs a separate license.
                        created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                        expires_at: "2026-10-24T16:10:00Z"
                        signed_at: "2026-09-27T11:15:00Z"
                        declined_at: null
                        metadata:
                          deal_id: RDG-FW26-014
                        created_at: "2026-09-24T16:10:00Z"
                      - id: ldr_dj05ema2gyfqqr7b22qj9ncm94
                        object: license_draft
                        livemode: true
                        status: declined
                        kind: issue
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                        license: null
                        license_request: null
                        scope:
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          modalities:
                            - image
                          kinds:
                            - depiction
                          purposes:
                            - advertising
                          commercial: true
                          channels:
                            - social
                            - web
                          territories:
                            - US
                            - CA
                          window:
                            starts_at: "2026-10-01T00:00:00-04:00"
                            ends_at: "2027-03-31T00:00:00-04:00"
                            time_zone: America/New_York
                          adjustments:
                            reframe: true
                            background_extension: true
                            lighting: true
                            text_overlay: true
                            body_and_age: false
                            expression: false
                            hair: false
                            pose: false
                            wardrobe: true
                            objects: true
                            skin_retouch: false
                            endorsement: false
                          prohibited_changes:
                            - body_and_age
                            - expression
                            - hair
                            - pose
                            - skin_retouch
                            - endorsement
                          required_attributes:
                            - identity.samePerson
                            - appearance.bodyAndAge
                            - appearance.expression
                            - appearance.hair
                            - appearance.pose
                            - appearance.skinRetouch
                            - context.endorsement
                          rules:
                            never:
                              - Do not show alcohol or tobacco.
                            always: []
                            brief: null
                          release_policy: per_output_review
                          escalation_window: P7D
                          final_deliverables: 24
                          sessions:
                            permitted: false
                          material_access: []
                          platforms:
                            mode: any_connected
                            accounts: []
                          sublicense: none
                          training: prohibited
                          disclosure: brand
                          attribution: null
                          post_revocation:
                            policy: retain
                          exclusivity:
                            exclusive: false
                            category: null
                          conflicts: []
                          compensation:
                            type: per_unit
                            per_unit:
                              units: placements
                              rate:
                                amount: 25000
                                currency: usd
                              per: 1
                            minimum:
                              amount: 500000
                              currency: usd
                            schedule: monthly
                        terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                        signer: talent
                        signing_url: null
                        signed_as_drafted: null
                        license_revision: null
                        decision_note: Send me Ridgeline's shot list first. I want to see the scenes before I sign.
                        note: Social and web in the US and Canada, October to March.
                        created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                        expires_at: "2026-10-22T14:45:00Z"
                        signed_at: null
                        declined_at: "2026-09-23T10:40:00Z"
                        metadata:
                          deal_id: RDG-FW26-014
                        created_at: "2026-09-22T14:45:00Z"
                    has_more: true
                    next_cursor: bGRyX2RqMDVlbWEyZ3lm…
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/license_drafts?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_drafts?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/license_drafts?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/license_drafts?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /license_drafts/{draft_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveLicenseDraft
      summary: Retrieve a license draft
      x-mint:
        href: /api-reference/license-drafts/retrieve-a-license-draft
        metadata:
          playground: simple
      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).

        Returns a draft with the full terms the signer sees and the `terms_digest` its revision will
        carry if it is signed as drafted. Once it is signed, `license`, `license_revision` and
        `signed_as_drafted` say what was signed.

        Restricted keys need `license_drafts:write`.
      tags: [License drafts]
      security:
        - { SecretKey: [license_drafts:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/LicenseDraftId"
      responses:
        "200":
          description: The draft.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseDraft" }
              examples:
                renewal: { $ref: "#/components/examples/LicenseDraft" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: updateLicenseDraft
      summary: Update a license draft
      x-mint:
        href: /api-reference/license-drafts/update-a-license-draft
        metadata:
          playground: simple
      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).

        Changes an open draft. Needs a mandate with `issue_licenses` for the talent. Fields you
        send replace the draft's; `scope` fields you omit keep their value. `terms_digest` changes with the terms, and `signing_url` stays the same: the
        signer always sees the current terms.

        Restricted keys need `license_drafts:write`.
      tags: [License drafts]
      security:
        - { SecretKey: [license_drafts:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/LicenseDraftId"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseDraftUpdate" }
            examples:
              narrow_channels:
                summary: Remove a channel before signature
                value:
                  scope:
                    channels:
                      - social
                      - web
                  note: Social and Ridgeline's own website only. TV needs a separate license.
      responses:
        "200":
          description: The updated draft.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseDraft" }
              examples:
                updated:
                  summary: The draft with its new terms and digest
                  value:
                    id: ldr_tw5hx5mq8q0j5wry9hp32ftj0p
                    object: license_draft
                    livemode: true
                    status: open
                    kind: issue
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: null
                    license_request: null
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                      modalities:
                        - image
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                        - CA
                      window:
                        starts_at: "2026-10-01T00:00:00-04:00"
                        ends_at: "2027-03-31T00:00:00-04:00"
                        time_zone: America/New_York
                      adjustments:
                        reframe: true
                        background_extension: true
                        lighting: true
                        text_overlay: true
                        body_and_age: false
                        expression: false
                        hair: false
                        pose: false
                        wardrobe: true
                        objects: true
                        skin_retouch: false
                        endorsement: false
                      prohibited_changes:
                        - body_and_age
                        - expression
                        - hair
                        - pose
                        - skin_retouch
                        - endorsement
                      required_attributes:
                        - identity.samePerson
                        - appearance.bodyAndAge
                        - appearance.expression
                        - appearance.hair
                        - appearance.pose
                        - appearance.skinRetouch
                        - context.endorsement
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: per_output_review
                      escalation_window: P7D
                      final_deliverables: 24
                      sessions:
                        permitted: false
                      material_access: []
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: brand
                      attribution: null
                      post_revocation:
                        policy: retain
                      exclusivity:
                        exclusive: false
                        category: null
                      conflicts: []
                      compensation:
                        type: per_unit
                        per_unit:
                          units: placements
                          rate:
                            amount: 25000
                            currency: usd
                          per: 1
                        minimum:
                          amount: 500000
                          currency: usd
                        schedule: monthly
                    terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                    signer: talent
                    signing_url: https://app.reflections.ai/sign/ldr_tw5hx5mq8q0j5wry9hp32ftj0p
                    signed_as_drafted: null
                    license_revision: null
                    decision_note: null
                    note: Social and Ridgeline's own website only. TV needs a separate license.
                    created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                    expires_at: "2026-10-24T16:10:00Z"
                    signed_at: null
                    declined_at: null
                    metadata:
                      deal_id: RDG-FW26-014
                    created_at: "2026-09-24T16:10:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY:?Set REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "scope": {
                "channels": [
                  "social",
                  "web"
                ]
              },
              "note": "Social and Ridgeline'\''s own website only. TV needs a separate license."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "scope": {
                  "channels": [
                    "social",
                    "web"
                  ]
                },
                "note": "Social and Ridgeline's own website only. TV needs a separate license."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "scope": {"channels": ["social", "web"]},
                "note": "Social and Ridgeline's own website only. TV needs a separate license.",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_UPDATE_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "scope": {
                    "channels": [
                      "social",
                      "web"
                    ]
                  },
                  "note": "Social and Ridgeline's own website only. TV needs a separate license."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /license_drafts/{draft_id}/discard:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: discardLicenseDraft
      summary: Discard a license draft
      x-mint:
        href: /api-reference/license-drafts/discard-a-license-draft
        metadata:
          playground: simple
      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).

        Discards an open draft. Needs a mandate with `issue_licenses` for the talent. Its `signing_url` stops working at once.

        Restricted keys need `license_drafts:write`.
      tags: [License drafts]
      security:
        - { SecretKey: [license_drafts:write] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/LicenseDraftId"
      responses:
        "200":
          description: The discarded draft.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseDraft" }
              examples:
                discarded:
                  summary: A discarded draft
                  value:
                    id: ldr_ddnyf8nhrged1gk09qg30hamjd
                    object: license_draft
                    livemode: true
                    status: discarded
                    kind: issue
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: null
                    license_request: null
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                      modalities:
                        - image
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                        - CA
                      window:
                        starts_at: "2026-10-01T00:00:00-04:00"
                        ends_at: "2027-03-31T00:00:00-04:00"
                        time_zone: America/New_York
                      adjustments:
                        reframe: true
                        background_extension: true
                        lighting: true
                        text_overlay: true
                        body_and_age: false
                        expression: false
                        hair: false
                        pose: false
                        wardrobe: true
                        objects: true
                        skin_retouch: false
                        endorsement: false
                      prohibited_changes:
                        - body_and_age
                        - expression
                        - hair
                        - pose
                        - skin_retouch
                        - endorsement
                      required_attributes:
                        - identity.samePerson
                        - appearance.bodyAndAge
                        - appearance.expression
                        - appearance.hair
                        - appearance.pose
                        - appearance.skinRetouch
                        - context.endorsement
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: per_output_review
                      escalation_window: P7D
                      final_deliverables: 24
                      sessions:
                        permitted: false
                      material_access: []
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: brand
                      attribution: null
                      post_revocation:
                        policy: retain
                      exclusivity:
                        exclusive: false
                        category: null
                      conflicts: []
                      compensation:
                        type: per_unit
                        per_unit:
                          units: placements
                          rate:
                            amount: 25000
                            currency: usd
                          per: 1
                        minimum:
                          amount: 500000
                          currency: usd
                        schedule: monthly
                    terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                    signer: representative
                    signing_url: null
                    signed_as_drafted: null
                    license_revision: null
                    decision_note: null
                    note: Social and web in the US and Canada, October to March.
                    created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                    expires_at: "2026-10-22T14:05:00Z"
                    signed_at: null
                    declined_at: null
                    metadata:
                      deal_id: RDG-FW26-014
                    created_at: "2026-09-22T14:05:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/MandateRequired" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY:?Set REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4/discard' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4/discard", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4/discard",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_DISCARD_LICENSE_DRAFT_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/license_drafts/ldr_hz4ngq81vhagynxm3ds9q2acz4/discard", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /webhook_endpoints:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createWebhookEndpoint
      summary: Create a webhook endpoint
      x-mint:
        href: /api-reference/webhook-endpoints/create-a-webhook-endpoint
        metadata:
          playground: simple
      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 HTTPS URL to receive events. The response includes the signing `secret` once;
        store it. Events are signed with the Standard Webhooks scheme.

        Restricted keys need `webhooks:manage`.
      tags: [Webhook endpoints]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/WebhookEndpointCreate" }
            examples:
              platform_events:
                summary: A platform's endpoint for connected licensees
                value:
                  url: https://northlight.example/webhooks/reflections
                  events:
                    - check.resolved
                    - generation.released
                    - generation.denied
                    - revocation.created
                    - session.terminated
                  description: Production
                  connected: true
      responses:
        "200":
          description: The endpoint, with its secret.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/WebhookEndpoint" }
              examples:
                webhook_endpoint: { $ref: "#/components/examples/WebhookEndpoint" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY:?Set REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/webhook_endpoints' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "url": "https://northlight.example/webhooks/reflections",
              "events": [
                "check.resolved",
                "generation.released",
                "generation.denied",
                "revocation.created",
                "session.terminated"
              ],
              "description": "Production",
              "connected": true
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/webhook_endpoints", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "url": "https://northlight.example/webhooks/reflections",
                "events": [
                  "check.resolved",
                  "generation.released",
                  "generation.denied",
                  "revocation.created",
                  "session.terminated"
                ],
                "description": "Production",
                "connected": true
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "url": "https://northlight.example/webhooks/reflections",
                "events": [
                    "check.resolved",
                    "generation.released",
                    "generation.denied",
                    "revocation.created",
                    "session.terminated",
                ],
                "description": "Production",
                "connected": True,
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/webhook_endpoints",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_CREATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "url": "https://northlight.example/webhooks/reflections",
                  "events": [
                    "check.resolved",
                    "generation.released",
                    "generation.denied",
                    "revocation.created",
                    "session.terminated"
                  ],
                  "description": "Production",
                  "connected": true
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/webhook_endpoints", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listWebhookEndpoints
      summary: List webhook endpoints
      x-mint:
        href: /api-reference/webhook-endpoints/list-webhook-endpoints
        metadata:
          playground: simple
      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).

        Lists your webhook endpoints, newest first: test-mode endpoints with a test key, live-mode
        endpoints with a live key. `secret` is `null` on every endpoint listed.

        Restricted keys need `webhooks:manage`.
      tags: [Webhook endpoints]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of endpoints.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/WebhookEndpointList" }
              examples:
                endpoints:
                  summary: Two endpoints, one disabled
                  value:
                    object: list
                    data:
                      - id: we_5x7z9b1d3f5h7k9m1p3r5t7v9x
                        object: webhook_endpoint
                        livemode: true
                        url: https://northlight.example/webhooks/reflections
                        events:
                          - check.resolved
                          - generation.released
                          - generation.denied
                          - revocation.created
                          - session.terminated
                        description: Production
                        status: enabled
                        disabled_reason: null
                        api_version: "2026-10-15"
                        connected: true
                        secret: null
                        metadata: {}
                        created_at: "2026-10-17T17:40:00Z"
                      - id: we_y18vejcjn8vvdfs468q4fzhtb2
                        object: webhook_endpoint
                        livemode: true
                        url: https://northlight.example/webhooks/revocations
                        events:
                          - revocation.created
                          - revocation.overdue
                          - license.suspended
                          - license.resumed
                          - license.revoked
                        description: Revocation worker
                        status: disabled
                        disabled_reason: Every delivery failed for 5 days. The last attempt timed out after 10 seconds.
                        api_version: "2026-10-15"
                        connected: true
                        secret: null
                        metadata:
                          team: trust-and-safety
                        created_at: "2026-09-14T10:30:00Z"
                    has_more: false
                    next_cursor: null
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/webhook_endpoints?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/webhook_endpoints?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/webhook_endpoints?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/webhook_endpoints?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /webhook_endpoints/{endpoint_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveWebhookEndpoint
      summary: Retrieve a webhook endpoint
      x-mint:
        href: /api-reference/webhook-endpoints/retrieve-a-webhook-endpoint
        metadata:
          playground: simple
      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).

        Returns a webhook endpoint. `secret` is `null`: it is returned only when the endpoint is
        created or its secret is rotated.

        Restricted keys need `webhooks:manage`.
      tags: [Webhook endpoints]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/WebhookEndpointId"
      responses:
        "200":
          description: The endpoint.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/WebhookEndpoint" }
              examples:
                webhook_endpoint:
                  summary: An enabled endpoint
                  value:
                    id: we_5x7z9b1d3f5h7k9m1p3r5t7v9x
                    object: webhook_endpoint
                    livemode: true
                    url: https://northlight.example/webhooks/reflections
                    events:
                      - check.resolved
                      - generation.released
                      - generation.denied
                      - revocation.created
                      - session.terminated
                    description: Production
                    status: enabled
                    disabled_reason: null
                    api_version: "2026-10-15"
                    connected: true
                    secret: null
                    metadata: {}
                    created_at: "2026-10-17T17:40:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: updateWebhookEndpoint
      summary: Update a webhook endpoint
      x-mint:
        href: /api-reference/webhook-endpoints/update-a-webhook-endpoint
        metadata:
          playground: simple
      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).

        Changes the URL, the events, the description, or re-enables a disabled endpoint.

        Restricted keys need `webhooks:manage`.
      tags: [Webhook endpoints]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/WebhookEndpointId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/WebhookEndpointUpdate" }
            examples:
              re_enable:
                summary: Re-enable a disabled endpoint
                value:
                  status: enabled
              change_events:
                summary: Change the events an endpoint receives
                value:
                  events:
                    - check.resolved
                    - generation.released
                    - generation.denied
                    - generation.expired
                    - revocation.created
                    - session.terminated
                    - license.suspended
                    - license.resumed
      responses:
        "200":
          description: The updated endpoint.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/WebhookEndpoint" }
              examples:
                re_enabled:
                  summary: An endpoint enabled again
                  value:
                    id: we_y18vejcjn8vvdfs468q4fzhtb2
                    object: webhook_endpoint
                    livemode: true
                    url: https://northlight.example/webhooks/revocations
                    events:
                      - revocation.created
                      - revocation.overdue
                      - license.suspended
                      - license.resumed
                      - license.revoked
                    description: Revocation worker
                    status: enabled
                    disabled_reason: null
                    api_version: "2026-10-15"
                    connected: true
                    secret: null
                    metadata:
                      team: trust-and-safety
                    created_at: "2026-09-14T10:30:00Z"
                events_changed:
                  summary: An endpoint with new events
                  value:
                    id: we_5x7z9b1d3f5h7k9m1p3r5t7v9x
                    object: webhook_endpoint
                    livemode: true
                    url: https://northlight.example/webhooks/reflections
                    events:
                      - check.resolved
                      - generation.released
                      - generation.denied
                      - generation.expired
                      - revocation.created
                      - session.terminated
                      - license.suspended
                      - license.resumed
                    description: Production
                    status: enabled
                    disabled_reason: null
                    api_version: "2026-10-15"
                    connected: true
                    secret: null
                    metadata: {}
                    created_at: "2026-10-17T17:40:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY:?Set REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "status": "enabled"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "status": "enabled"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"status": "enabled"}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_UPDATE_WEBHOOK_ENDPOINT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "status": "enabled"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }
    delete:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: deleteWebhookEndpoint
      summary: Delete a webhook endpoint
      x-mint:
        href: /api-reference/webhook-endpoints/delete-a-webhook-endpoint
        metadata:
          playground: simple
      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).

        Deletes a webhook endpoint. No further events are sent to it.

        Restricted keys need `webhooks:manage`.
      tags: [Webhook endpoints]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/WebhookEndpointId"
      responses:
        "200":
          description: The deleted endpoint.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/DeletedObject" }
              examples:
                deleted:
                  summary: A deleted endpoint
                  value:
                    id: we_crgx8fydpc71dmc71rtev3w906
                    object: webhook_endpoint
                    deleted: true
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X DELETE 'https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x", {
              method: "DELETE",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x",
                              method="DELETE", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("DELETE", "https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /webhook_endpoints/{endpoint_id}/rotate_secret:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: rotateWebhookEndpointSecret
      summary: Rotate a webhook secret
      x-mint:
        href: /api-reference/webhook-endpoints/rotate-a-webhook-secret
        metadata:
          playground: simple
      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).

        Issues a new signing secret. For 24 hours, events carry signatures from both the old and
        the new secret, so you can deploy the new one without dropping events.

        Restricted keys need `webhooks:manage`.
      tags: [Webhook endpoints]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/IdempotencyKey"
        - $ref: "#/components/parameters/WebhookEndpointId"
      responses:
        "200":
          description: The endpoint, with its new secret.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/WebhookEndpoint" }
              examples:
                rotated:
                  summary: The endpoint with its new secret
                  value:
                    id: we_5x7z9b1d3f5h7k9m1p3r5t7v9x
                    object: webhook_endpoint
                    livemode: true
                    url: https://northlight.example/webhooks/reflections
                    events:
                      - check.resolved
                      - generation.released
                      - generation.denied
                      - revocation.created
                      - session.terminated
                    description: Production
                    status: enabled
                    disabled_reason: null
                    api_version: "2026-10-15"
                    connected: true
                    secret: whsec_Gt/AXBvBaZqsmttDc5OIMUyzYRxzPEa5
                    metadata: {}
                    created_at: "2026-10-17T17:40:00Z"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY:?Set REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x/rotate_secret' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x/rotate_secret", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
            }
            request = Request("https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x/rotate_secret",
                              method="POST", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_ROTATE_WEBHOOK_ENDPOINT_SECRET_IDEMPOTENCY_KEY before running this example")
                }

                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/webhook_endpoints/we_5x7z9b1d3f5h7k9m1p3r5t7v9x/rotate_secret", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /events:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: listEvents
      summary: List events
      x-mint:
        href: /api-reference/events/list-events
        metadata:
          playground: simple
      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).

        Lists events from the last 30 days, newest first, or oldest first after `after`.

        Restricted keys need `events:read`.
      tags: [Events]
      security:
        - { SecretKey: [events:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - name: type
          in: query
          description: Only events of this type. Use a prefix with `*`, such as `license.*`.
          schema: { type: string }
        - name: after
          in: query
          description: Return events created after this one, oldest first.
          schema: { type: string, pattern: "^evt_[0-9a-hjkmnp-tv-z]{26}$" }
        - $ref: "#/components/parameters/Limit"
        - $ref: "#/components/parameters/Cursor"
      responses:
        "200":
          description: A page of events.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/EventList" }
              examples:
                mandate_events:
                  summary: Mandate events, filtered by type
                  value:
                    object: list
                    data:
                      - id: evt_72z7c0jm4ezmm1xzvtmp4j6tm4
                        object: event
                        type: mandate.ended
                        api_version: "2026-10-15"
                        livemode: true
                        account: null
                        sequence: 2
                        created_at: "2026-10-29T13:02:11Z"
                        data:
                          object:
                            id: mnd_ww2cs3e4j5tgqqxs7mt7746q4p
                            object: mandate
                            livemode: true
                            talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                            talent_name: Jonah Reyes
                            representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                            role: manager
                            powers:
                              - issue_licenses
                              - review_outputs
                              - receive_statements
                            status: ended
                            starts_at: "2026-10-05T15:20:00Z"
                            ends_at: null
                            ended_at: "2026-10-29T13:02:10Z"
                            revocation: rvk_ch7rn89symf3em1rsp31ztxg9b
                            created_at: "2026-10-05T15:20:00Z"
                          previous_attributes:
                            status: active
                            ended_at: null
                            revocation: null
                      - id: evt_td2daf8rebqk19qb6bbfss9j0w
                        object: event
                        type: mandate.created
                        api_version: "2026-10-15"
                        livemode: true
                        account: null
                        sequence: 1
                        created_at: "2026-10-05T15:20:01Z"
                        data:
                          object:
                            id: mnd_ww2cs3e4j5tgqqxs7mt7746q4p
                            object: mandate
                            livemode: true
                            talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                            talent_name: Jonah Reyes
                            representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                            role: manager
                            powers:
                              - issue_licenses
                              - review_outputs
                              - receive_statements
                            status: active
                            starts_at: "2026-10-05T15:20:00Z"
                            ends_at: null
                            ended_at: null
                            revocation: null
                            created_at: "2026-10-05T15:20:00Z"
                    has_more: false
                    next_cursor: null
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/events?limit=10' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/events?limit=10", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/events?limit=10",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/events?limit=10", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /events/{event_id}:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveEvent
      summary: Retrieve an event
      x-mint:
        href: /api-reference/events/retrieve-an-event
        metadata:
          playground: simple
      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).

        Returns an event from the last 30 days, with `data.object` as it was when the event
        happened. Retrieve the object itself for its current state.

        Restricted keys need `events:read`.
      tags: [Events]
      security:
        - { SecretKey: [events:read] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/EventId"
      responses:
        "200":
          description: The event.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/AnyEvent" }
              examples:
                check_resolved_event: { $ref: "#/components/examples/CheckResolvedEvent" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"

            curl --fail-with-body --max-time 30 'https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15"
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h", {
              method: "GET",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
              },
              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 os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
            }
            request = Request("https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h",
                              method="GET", headers=headers)
            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"
                "os"
                "time"
            )

            func main() {
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }

                request, err := http.NewRequest("GET", "https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h", nil)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                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))
            }

  /events/{event_id}/resend:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: resendEvent
      summary: Resend an event
      x-mint:
        href: /api-reference/events/resend-an-event
        metadata:
          playground: simple
      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).

        Delivers an event again to one endpoint, or to every endpoint subscribed to its type.

        Restricted keys need `webhooks:manage`.
      tags: [Events]
      security:
        - { SecretKey: [webhooks:manage] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/EventId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                endpoint:
                  type: string
                  pattern: "^we_[0-9a-hjkmnp-tv-z]{26}$"
                  description: Resend only to this endpoint.
            examples:
              one_endpoint:
                summary: Resend to one endpoint
                value:
                  endpoint: we_y18vejcjn8vvdfs468q4fzhtb2
      responses:
        "200":
          description: The event, queued for delivery.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/AnyEvent" }
              examples:
                queued:
                  summary: A missed revocation, queued again
                  value:
                    id: evt_d3m3h3ycs6hxt7k37pam23cw1t
                    object: event
                    type: revocation.created
                    api_version: "2026-10-15"
                    livemode: true
                    account: null
                    sequence: 1
                    created_at: "2026-10-17T18:03:41Z"
                    data:
                      object:
                        id: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                        object: revocation
                        livemode: true
                        scope: license
                        targets:
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          licenses:
                            - lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                          facets:
                            - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                          mandate: null
                        status: pending_acknowledgement
                        initiated_by: talent
                        for_cause: false
                        cause: null
                        note: null
                        effective_at: "2026-10-17T18:03:40Z"
                        post_revocation:
                          policy: retain
                          withdraw_by: null
                        required_actions:
                          - stop_generation
                          - purge_cached_decisions
                          - delete_provider_copies
                        provider_copies:
                          - facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                            provider: example-voice-provider
                            external_id: vx_4f9a2c
                        affected:
                          checks_denied: 3
                          generations_denied: 0
                          sessions_terminated: 1
                          released_outputs: 418
                        acknowledge_by: "2026-10-18T18:03:40Z"
                        acknowledgements: []
                        created_at: "2026-10-17T18:03:40Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY:?Set REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h/resend' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "endpoint": "we_y18vejcjn8vvdfs468q4fzhtb2"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h/resend", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "endpoint": "we_y18vejcjn8vvdfs468q4fzhtb2"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"endpoint": "we_y18vejcjn8vvdfs468q4fzhtb2"}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h/resend",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_RESEND_EVENT_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "endpoint": "we_y18vejcjn8vvdfs468q4fzhtb2"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/events/evt_1h3k5m7p9r1t3v5x7z9b1d3f5h/resend", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /test_helpers/escalations/{escalation_id}/resolve:
    post:
      x-reflections-availability: { test: available, live: unavailable }
      operationId: resolveTestEscalation
      summary: Resolve an escalation
      x-mint:
        href: /api-reference/test-helpers/resolve-an-escalation
      description: |
        **Test mode available. Live mode unavailable.** Resolves only your sandbox checks and generations. Requires an unrestricted test key; no webhook is sent.

        Test mode only. Answers an open escalation as its reviewer would, so you can exercise
        `check.resolved`, `generation.released` and `generation.denied` without a person.

        Needs an unrestricted key.
      tags: [Test helpers]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - name: escalation_id
          in: path
          required: true
          description: The escalation's ID, from `escalation.id` on the check or generation.
          example: esc_2rmfs05fb533m38c9vtj2v36p3
          schema: { type: string, pattern: "^esc_[0-9a-hjkmnp-tv-z]{26}$" }
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [decision]
              properties:
                decision: { type: string, enum: [allow, deny, expire], description: "`allow` or `deny` decides as a reviewer would; `expire` lets the hold run out." }
                note: { type: string, maxLength: 500, description: "Shown as the reviewer's note." }
            examples:
              release:
                summary: Release a held output
                value:
                  decision: allow
                  note: Approved.
              decline:
                summary: Decline a held output
                value:
                  decision: deny
                  note: Not this pose.
      responses:
        "200":
          description: The resolved escalation's check or generation, as an event would carry it.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/Check"
                  - $ref: "#/components/schemas/Generation"
              examples:
                released:
                  summary: The released generation, with its receipt
                  value:
                    id: gen_bve7nfxeetkbstsfvqmvp4xjrr
                    object: generation
                    livemode: false
                    check: chk_nzrafkmpsmvkq48bptr2jjkakv
                    session: null
                    candidate_index: 0
                    artifact:
                      file: file_gtxcsn02378bp8ms55h89gnny5
                      sha256: d9c3fa0c6745dce267ccda24cd633f480cbcc47ec66f81840501f88ede082127
                      media_type: image/png
                      duration_ms: null
                    execution:
                      provider: example-image-provider
                      model: image-model-3
                      job_id: job_88391
                    findings:
                      - term: license:lic_31x87g772xdcz1n1za29601rbt/terms.requiredAttributes
                        attribute: identity.samePerson
                        result: preserved
                    unchecked_terms: []
                    assurance: observed
                    watermark: null
                    metadata: {}
                    created_at: "2026-10-17T18:20:00Z"
                    status: released
                    decision: allow
                    reasons: []
                    obligations:
                      - type: c2pa_manifest
                    escalation:
                      id: esc_2rmfs05fb533m38c9vtj2v36p3
                      reason: release_review
                      reviewer: talent
                      status: allowed
                      expires_at: "2026-10-24T18:20:00Z"
                      resolved_at: "2026-10-17T18:26:14Z"
                      note: Approved.
                    receipt: rcpt_3e6gk07nyfq5v9vez6qr5t34bk
                    c2pa:
                      label: ai.reflections.license
                      data:
                        receipt: eyJhbGciOiJFUzI1NiIs…
                        verify_url: https://app.reflections.ai/r/rcpt_3e6gk07nyfq5v9vez6qr5t34bk
                    decided_at: "2026-10-17T18:26:14Z"
                declined:
                  summary: The declined generation
                  value:
                    id: gen_bve7nfxeetkbstsfvqmvp4xjrr
                    object: generation
                    livemode: false
                    check: chk_nzrafkmpsmvkq48bptr2jjkakv
                    session: null
                    candidate_index: 0
                    artifact:
                      file: file_gtxcsn02378bp8ms55h89gnny5
                      sha256: d9c3fa0c6745dce267ccda24cd633f480cbcc47ec66f81840501f88ede082127
                      media_type: image/png
                      duration_ms: null
                    execution:
                      provider: example-image-provider
                      model: image-model-3
                      job_id: job_88391
                    findings:
                      - term: license:lic_31x87g772xdcz1n1za29601rbt/terms.requiredAttributes
                        attribute: identity.samePerson
                        result: preserved
                    unchecked_terms: []
                    assurance: observed
                    watermark: null
                    metadata: {}
                    created_at: "2026-10-17T18:20:00Z"
                    status: denied
                    decision: deny
                    reasons:
                      - code: review_declined
                        stage: generation
                        talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                        sentence: Jonah Reyes declined to release this output.
                    obligations: []
                    escalation:
                      id: esc_2rmfs05fb533m38c9vtj2v36p3
                      reason: release_review
                      reviewer: talent
                      status: denied
                      expires_at: "2026-10-24T18:20:00Z"
                      resolved_at: "2026-10-17T18:26:14Z"
                      note: Not this pose.
                    receipt: rcpt_5mk7pbjd6q2nxk5b6qqdsh1m25
                    c2pa: null
                    decided_at: "2026-10-17T18:26:14Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY:?Set REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/test_helpers/escalations/esc_2rmfs05fb533m38c9vtj2v36p3/resolve' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "decision": "allow",
              "note": "Approved."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/test_helpers/escalations/esc_2rmfs05fb533m38c9vtj2v36p3/resolve", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "decision": "allow",
                "note": "Approved."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"decision": "allow", "note": "Approved."}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/test_helpers/escalations/esc_2rmfs05fb533m38c9vtj2v36p3/resolve",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_RESOLVE_TEST_ESCALATION_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "decision": "allow",
                  "note": "Approved."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/test_helpers/escalations/esc_2rmfs05fb533m38c9vtj2v36p3/resolve", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /test_helpers/license_requests/{request_id}/sign:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: signTestLicenseRequest
      summary: Sign a license request
      x-mint:
        href: /api-reference/test-helpers/sign-a-license-request
        metadata:
          playground: simple
      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).

        Test mode only. Signs a license request to a sandbox talent as the talent would. A request
        of kind `new` issues a license in `pending_acceptance`; a request of kind `change` signs a
        new revision into the license's `pending_revision`. Pass `accept: true` to accept either in
        the same call, as the licensee would.

        Needs an unrestricted key.
      tags: [Test helpers]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseRequestId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                accept: { type: boolean, default: false, description: "Also accept the license as the licensee, so it is `active` at once." }
                decline: { type: boolean, default: false, description: Decline the request instead. }
            examples:
              sign_and_accept:
                summary: Sign as the talent and accept
                value:
                  accept: true
      responses:
        "200":
          description: The license request, with the license it became.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseRequest" }
              examples:
                signed:
                  summary: A new license request, signed
                  value:
                    id: lrq_pdgtby01k8ejkffqkpdwdv9w7b
                    object: license_request
                    livemode: false
                    kind: new
                    status: signed
                    talent: tal_7q9s1v3w5y7a9c1e3g5h7k9m1n
                    licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                    license: lic_qx46g3vknbm1jsx6ac526rwkfb
                    license_revision: lrv_zy4xrqfs85ek8j1yt63x8c061v
                    check: chk_9r1s3t5v7w9x1y3z5a7b9c1d3e
                    requested_scope:
                      facet_types:
                        - likeness
                      modalities:
                        - image
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                      territories:
                        - US
                      starts_at: "2026-11-01T00:00:00Z"
                      ends_at: "2027-01-31T23:59:59Z"
                      final_deliverables: 20
                    offer:
                      type: flat
                      flat:
                        amount: 1500000
                        currency: usd
                      schedule: on_acceptance
                    note: Winter trail campaign, three months, social and our site.
                    decision_note: null
                    signed_at: "2026-10-16T14:07:30Z"
                    declined_at: null
                    withdrawn_at: null
                    metadata: {}
                    created_at: "2026-10-16T14:05:12Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY:?Set REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/test_helpers/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/sign' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "accept": true
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/test_helpers/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/sign", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "accept": true
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"accept": True}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/test_helpers/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/sign",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_SIGN_TEST_LICENSE_REQUEST_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "accept": true
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/test_helpers/license_requests/lrq_py3xqfvbjjcdhvf33y6c2w26jm/sign", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /test_helpers/licenses/{license_id}/accept:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: acceptTestLicense
      summary: Accept a license
      x-mint:
        href: /api-reference/test-helpers/accept-a-license
        metadata:
          playground: simple
      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).

        Test mode only. Accepts or declines a test license as the licensee would on its acceptance
        page: the license itself while `pending_acceptance`, or else its `pending_revision`. Sends
        the same events a live acceptance sends. A license with nothing waiting returns
        `409 invalid_state_transition`.

        Needs an unrestricted key.
      tags: [Test helpers]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                decision: { type: string, enum: [accept, decline], default: accept, description: "Accept or decline the pending revision as the licensee would." }
            examples:
              accept:
                summary: Accept the pending revision
                value:
                  decision: accept
      responses:
        "200":
          description: The license after the decision.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/License" }
              examples:
                revision_accepted:
                  summary: Revision 2 in force
                  value:
                    id: lic_97bb8qgh1b9zk81anbjkmprxh4
                    object: license
                    livemode: false
                    status: active
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    issued_by:
                      party: talent
                      account: null
                    handle: T8M3QX
                    current_revision: lrv_f96ktjt9bw2j3xg69xbnt1xrqa
                    revision_number: 2
                    pending_revision: null
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                      modalities:
                        - image
                        - video
                        - speech
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                        - tv
                      territories:
                        - US
                        - CA
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: after_checks
                      sessions:
                        permitted: false
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: licensed
                      post_revocation:
                        policy: withdraw
                        withdraw_within: P7D
                    acceptance_url: null
                    accepted_at: "2026-09-02T10:00:00Z"
                    suspended_at: null
                    revoked_at: null
                    declined_at: null
                    metadata: {}
                    created_at: "2026-09-02T10:00:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY:?Set REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/accept' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "decision": "accept"
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/accept", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "decision": "accept"
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({"decision": "accept"}).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/accept",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_ACCEPT_TEST_LICENSE_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "decision": "accept"
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/accept", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /test_helpers/licenses/{license_id}/revoke:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: revokeTestLicense
      summary: Revoke a license
      x-mint:
        href: /api-reference/test-helpers/revoke-a-license
        metadata:
          playground: simple
      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).

        Test mode only. Revokes or suspends a test license as its talent would, and sends the same
        events, stream messages and revocation a live revocation sends.

        Needs an unrestricted key.
      tags: [Test helpers]
      security:
        - { SecretKey: [] }
      parameters:
        - $ref: "#/components/parameters/ReflectionsVersion"
        - $ref: "#/components/parameters/ReflectionsAccount"
        - $ref: "#/components/parameters/LicenseId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                action: { type: string, enum: [revoke, suspend, resume], default: revoke, description: "`suspend` pauses the license until `resume`; `revoke` ends it." }
                for_cause: { type: boolean, default: false, description: "Revoke for a breach of the license, stated in `cause`. Only a revocation for cause can withdraw released outputs." }
                cause: { type: string, maxLength: 1000, description: "Required when `for_cause` is `true`." }
            examples:
              revoke_for_cause:
                summary: Revoke for cause
                value:
                  action: revoke
                  for_cause: true
                  cause: Outputs used outside the licensed territories.
              suspend:
                summary: Suspend
                value:
                  action: suspend
      responses:
        "200":
          description: The license after the action.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            RateLimit: { $ref: "#/components/headers/RateLimit" }
            RateLimit-Policy: { $ref: "#/components/headers/RateLimitPolicy" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/License" }
              examples:
                revoked:
                  summary: The license, revoked
                  value:
                    id: lic_97bb8qgh1b9zk81anbjkmprxh4
                    object: license
                    livemode: false
                    status: revoked
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    issued_by:
                      party: talent
                      account: null
                    handle: T8M3QX
                    current_revision: lrv_f96ktjt9bw2j3xg69xbnt1xrqa
                    revision_number: 2
                    pending_revision: null
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                      modalities:
                        - image
                        - video
                        - speech
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                        - tv
                      territories:
                        - US
                        - CA
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: after_checks
                      sessions:
                        permitted: false
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: licensed
                      post_revocation:
                        policy: withdraw
                        withdraw_within: P7D
                    acceptance_url: null
                    accepted_at: "2026-09-02T10:00:00Z"
                    suspended_at: null
                    revoked_at: "2026-10-17T19:40:22Z"
                    declined_at: null
                    metadata: {}
                    created_at: "2026-09-02T10:00:00Z"
                suspended:
                  summary: The license, suspended
                  value:
                    id: lic_97bb8qgh1b9zk81anbjkmprxh4
                    object: license
                    livemode: false
                    status: suspended
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                    issued_by:
                      party: talent
                      account: null
                    handle: T8M3QX
                    current_revision: lrv_f96ktjt9bw2j3xg69xbnt1xrqa
                    revision_number: 2
                    pending_revision: null
                    scope:
                      facets:
                        - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                      modalities:
                        - image
                        - video
                        - speech
                      kinds:
                        - depiction
                      purposes:
                        - advertising
                      commercial: true
                      channels:
                        - social
                        - web
                        - tv
                      territories:
                        - US
                        - CA
                      rules:
                        never:
                          - Do not show alcohol or tobacco.
                        always: []
                        brief: null
                      release_policy: after_checks
                      sessions:
                        permitted: false
                      platforms:
                        mode: any_connected
                        accounts: []
                      sublicense: none
                      training: prohibited
                      disclosure: licensed
                      post_revocation:
                        policy: withdraw
                        withdraw_within: P7D
                    acceptance_url: null
                    accepted_at: "2026-09-02T10:00:00Z"
                    suspended_at: "2026-10-17T19:40:22Z"
                    revoked_at: null
                    declined_at: null
                    metadata: {}
                    created_at: "2026-09-02T10:00:00Z"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
        "404": { $ref: "#/components/responses/NotFound" }
        "409": { $ref: "#/components/responses/Conflict" }
        "422": { $ref: "#/components/responses/Unprocessable" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            # Set a unique key once per new action; persist it and reuse it for every retry.
            : "${REFLECTIONS_KEY:?Set REFLECTIONS_KEY before running this example}"
            : "${REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY:?Set REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revoke' \
              -H "Authorization: Bearer $REFLECTIONS_KEY" \
              -H "Reflections-Version: 2026-10-15" \
              -H "Idempotency-Key: $REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY" \
              -H "Content-Type: application/json" \
              --data-raw '{
              "action": "revoke",
              "for_cause": true,
              "cause": "Outputs used outside the licensed territories."
            }'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";

            // Set a unique key once per new action; persist it and reuse it for every retry.
            const apiKey = env.REFLECTIONS_KEY;
            if (!apiKey) throw new Error("Set REFLECTIONS_KEY before running this example");
            const idempotencyKey = env.REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY;
            if (!idempotencyKey) throw new Error("Set REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY before running this example");

            const response = await fetch("https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revoke", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${apiKey}`,
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "action": "revoke",
                "for_cause": true,
                "cause": "Outputs used outside the licensed territories."
              }),
              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
            import os
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            # Set a unique key once per new action; persist it and reuse it for every retry.
            apiKey = os.environ["REFLECTIONS_KEY"]
            if not apiKey:
                raise ValueError("Set REFLECTIONS_KEY before running this example")
            idempotencyKey = os.environ["REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY"]
            if not idempotencyKey:
                raise ValueError("Set REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY before running this example")

            headers = {
                "Authorization": f"Bearer {apiKey}",
                "Reflections-Version": "2026-10-15",
                "Idempotency-Key": idempotencyKey,
                "Content-Type": "application/json",
            }
            data = json.dumps({
                "action": "revoke",
                "for_cause": True,
                "cause": "Outputs used outside the licensed territories.",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revoke",
                              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"
                "os"
                "strings"
                "time"
            )

            func main() {
                // Set a unique key once per new action; persist it and reuse it for every retry.
                apiKey := os.Getenv("REFLECTIONS_KEY")
                if apiKey == "" {
                    panic("Set REFLECTIONS_KEY before running this example")
                }
                idempotencyKey := os.Getenv("REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY")
                if idempotencyKey == "" {
                    panic("Set REFLECTIONS_REVOKE_TEST_LICENSE_IDEMPOTENCY_KEY before running this example")
                }

                body := strings.NewReader(`{
                  "action": "revoke",
                  "for_cause": true,
                  "cause": "Outputs used outside the licensed territories."
                }`)
                request, err := http.NewRequest("POST", "https://app.reflections.ai/v1/test_helpers/licenses/lic_k5zba2q8v1m3n7p4r6s9t0wxyh/revoke", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Authorization", "Bearer " + apiKey)
                request.Header.Set("Reflections-Version", "2026-10-15")
                request.Header.Set("Idempotency-Key", idempotencyKey)
                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))
            }

  /.well-known/talent-license:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveDiscoveryDocument
      summary: Retrieve the discovery document
      x-mint:
        href: /api-reference/discovery/retrieve-the-discovery-document
      description: |
        **Test mode available. Live mode available.** One public document serves both modes; it needs no key.

        Lists this license server's endpoints, supported protocol and API versions, signed token
        types and obligation types. Platforms, generation tools and verifiers read it instead of
        hard-coding URLs. Public; cache it for its `Cache-Control` max-age. See
        [Discovery](/api-reference/formats/discovery).
      tags: [Discovery]
      servers:
        - url: https://app.reflections.ai
      security: []
      responses:
        "200":
          description: The discovery document.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/DiscoveryDocument" }
              examples:
                reflections: { $ref: "#/components/examples/DiscoveryDocument" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            curl --fail-with-body --max-time 30 'https://app.reflections.ai/.well-known/talent-license'
        - lang: typescript
          label: TypeScript
          source: |
            import { exit } from "node:process";

            const response = await fetch("https://app.reflections.ai/.well-known/talent-license", {
              method: "GET",
              headers: {
              },
              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: |
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            headers = {
            }
            request = Request("https://app.reflections.ai/.well-known/talent-license",
                              method="GET", headers=headers)
            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"
                "time"
            )

            func main() {
                request, err := http.NewRequest("GET", "https://app.reflections.ai/.well-known/talent-license", nil)
                if err != nil {
                    panic(err)
                }
                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))
            }
  /.well-known/jwks.json:
    get:
      x-reflections-availability: { test: available, live: available }
      operationId: retrieveJwks
      summary: Retrieve the signing keys
      x-mint:
        href: /api-reference/discovery/retrieve-the-signing-keys
      description: |
        **Test mode available. Live mode available.** Public, with no key. The set holds the `rfl-test-` keys that sign sandbox tokens and receipts and the live keys published before live signing is activated. A published live key does not mean live signing is active.

        The JWKS that holds the public keys for every authorization token, session token and
        receipt. Public, and served with `Cache-Control: public, max-age=3600`. Cache it for that
        hour, and fetch it again when a token names a `kid` you do not have, at most once per hour.
        Retired keys stay published so old receipts keep verifying.
      tags: [Discovery]
      servers:
        - url: https://app.reflections.ai
      security: []
      responses:
        "200":
          description: The key set.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Jwks" }
              examples:
                keys: { $ref: "#/components/examples/Jwks" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            curl --fail-with-body --max-time 30 'https://app.reflections.ai/.well-known/jwks.json'
        - lang: typescript
          label: TypeScript
          source: |
            import { exit } from "node:process";

            const response = await fetch("https://app.reflections.ai/.well-known/jwks.json", {
              method: "GET",
              headers: {
              },
              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: |
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            headers = {
            }
            request = Request("https://app.reflections.ai/.well-known/jwks.json",
                              method="GET", headers=headers)
            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"
                "time"
            )

            func main() {
                request, err := http.NewRequest("GET", "https://app.reflections.ai/.well-known/jwks.json", nil)
                if err != nil {
                    panic(err)
                }
                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))
            }
  /oauth/authorize:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: authorizeClient
      summary: Authorize a client
      x-mint:
        href: /api-reference/oauth/authorize-a-client
        metadata:
          playground: simple
      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.
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security: []
      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" }
      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)
            }

  /oauth/token:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createAccessToken
      summary: Create an access token
      x-mint:
        href: /api-reference/oauth/create-an-access-token
        metadata:
          playground: simple
      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).

        Exchanges a grant for an access token, as OAuth 2.0 (RFC 6749) defines. The body is
        form-encoded.

        - `authorization_code`: an MCP client redeems the code from the
          [authorization page](/api-reference/oauth/authorize-a-client) with its `code_verifier`.
          It receives a `Bearer` access token for the MCP server, valid for one hour, and a
          refresh token.
        - `refresh_token`: exchanges a refresh token for a new access token and a new refresh
          token. The old refresh token stops working. Send `scope` to narrow the new token.
        - `client_credentials`: an [RSL](/standard/interop/rsl) client requests a `License`
          token for a talent's facet, sending the RSL `<license>` it wants as `license` and the
          facet's IRI as `resource`. Reflections issues it only when your account holds a license
          that covers the usage, or the talent's posture allows the usage without one. A `License`
          token is not an authorization to generate: check the use with
          [`POST /v1/checks`](/api-reference/checks/create-a-check) before you generate.

        A code issued to a platform's `client_id` is refused here with `unauthorized_client`:
        platforms redeem codes at [`POST /v1/connections`](/api-reference/connections/create-a-connection)
        and act with their secret key, not with access tokens.

        The token endpoint takes no key. A public client, such as a desktop agent, sends its
        `client_id` in the body. A confidential client authenticates with its client ID and
        secret, and `client_credentials` needs one. Errors are OAuth errors (RFC 6749 §5.2), not
        problem details; `429` and `5xx` responses are problem details, as everywhere else.
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security:
        - {}
        - ClientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema: { $ref: "#/components/schemas/AccessTokenCreate" }
            examples:
              authorization_code:
                summary: An MCP client redeems a code
                value:
                  grant_type: authorization_code
                  code: ac_8Xgcqs0ZRUe0M57eyADP9yT4
                  redirect_uri: http://127.0.0.1:33418/oauth/callback
                  code_verifier: 6l_CpK7wrBmjR_geDznNZuKR9du8tNl4p8wxTb6jJ9o
                  client_id: cl_ra8t5tsberxpax0351jdyqgrb7
                  resource: https://app.reflections.ai/mcp
              refresh_token:
                summary: An MCP client refreshes its token
                value:
                  grant_type: refresh_token
                  refresh_token: rrt_0so8SAbeT5SQ2Zn97lnj_3usT_hvHXda
                  client_id: cl_ra8t5tsberxpax0351jdyqgrb7
                  resource: https://app.reflections.ai/mcp
              rsl_license:
                summary: An RSL client requests a License token
                value:
                  grant_type: client_credentials
                  resource: https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                  license: <license><permits type="usage">ai-input</permits><permits type="user">commercial</permits><permits type="geo">US CA</permits></license>
      responses:
        "200":
          description: The access token.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            Cache-Control:
              description: Always `no-store`.
              schema: { type: string, example: no-store }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/AccessToken" }
              examples:
                bearer:
                  summary: A token for the MCP server
                  value:
                    access_token: rat_x6U8znpCLsAr4BolEF6a8WP4tYxIDW6A
                    token_type: Bearer
                    expires_in: 3600
                    refresh_token: rrt_Hq2Lw7Vb4Nc9Xk1Mz6Tr3Ys8Pd5Gf0Aj
                    scope: talent:read licenses:read checks:write generations:write
                    livemode: false
                license:
                  summary: An RSL License token
                  value:
                    access_token: rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV
                    token_type: License
                    expires_in: 86400
                    livemode: true
        "400":
          description: |
            The grant is invalid. `error` is `invalid_request` (a missing or repeated parameter),
            `invalid_grant` (an unknown, expired or used code, a `code_verifier` or `redirect_uri`
            that does not match, a revoked refresh token, or an RSL usage no license or posture
            covers), `unauthorized_client` (a platform's code, or a grant the client did not
            register), `unsupported_grant_type`, `invalid_scope` or `invalid_target` (a `resource`
            this server does not serve).
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/OAuthError" }
              examples:
                invalid_grant:
                  summary: The code was already used
                  value:
                    error: invalid_grant
                    error_description: The authorization code was already used. Send the person through the authorization page again.
                platform_code:
                  summary: A platform's code
                  value:
                    error: unauthorized_client
                    error_description: Codes issued to a platform are redeemed at POST /v1/connections.
        "401":
          description: The client ID or secret is wrong. `error` is `invalid_client`.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
            WWW-Authenticate:
              description: "`Basic realm=\"reflections\"`."
              schema: { type: string }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/OAuthError" }
              example:
                error: invalid_client
                error_description: Client authentication failed.
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/token' \
              -H "Content-Type: application/x-www-form-urlencoded" \
              --data-urlencode 'grant_type=authorization_code' \
              --data-urlencode 'code=ac_8Xgcqs0ZRUe0M57eyADP9yT4' \
              --data-urlencode 'redirect_uri=http://127.0.0.1:33418/oauth/callback' \
              --data-urlencode 'code_verifier=6l_CpK7wrBmjR_geDznNZuKR9du8tNl4p8wxTb6jJ9o' \
              --data-urlencode 'client_id=cl_ra8t5tsberxpax0351jdyqgrb7' \
              --data-urlencode 'resource=https://app.reflections.ai/mcp'
        - lang: typescript
          label: TypeScript
          source: |
            import { exit } from "node:process";

            const response = await fetch("https://app.reflections.ai/oauth/token", {
              method: "POST",
              headers: {
                "Content-Type": "application/x-www-form-urlencoded",
              },
              body: new URLSearchParams({
                "grant_type": "authorization_code",
                "code": "ac_8Xgcqs0ZRUe0M57eyADP9yT4",
                "redirect_uri": "http://127.0.0.1:33418/oauth/callback",
                "code_verifier": "6l_CpK7wrBmjR_geDznNZuKR9du8tNl4p8wxTb6jJ9o",
                "client_id": "cl_ra8t5tsberxpax0351jdyqgrb7",
                "resource": "https://app.reflections.ai/mcp"
              }),
              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: |
            from urllib.error import HTTPError
            from urllib.parse import urlencode
            from urllib.request import Request, urlopen

            headers = {
                "Content-Type": "application/x-www-form-urlencoded",
            }
            data = urlencode({
                "grant_type": "authorization_code",
                "code": "ac_8Xgcqs0ZRUe0M57eyADP9yT4",
                "redirect_uri": "http://127.0.0.1:33418/oauth/callback",
                "code_verifier": "6l_CpK7wrBmjR_geDznNZuKR9du8tNl4p8wxTb6jJ9o",
                "client_id": "cl_ra8t5tsberxpax0351jdyqgrb7",
                "resource": "https://app.reflections.ai/mcp",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/oauth/token",
                              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"
                "net/url"
                "strings"
                "time"
            )

            func main() {
                form := url.Values{
                    "grant_type": {"authorization_code"},
                    "code": {"ac_8Xgcqs0ZRUe0M57eyADP9yT4"},
                    "redirect_uri": {"http://127.0.0.1:33418/oauth/callback"},
                    "code_verifier": {"6l_CpK7wrBmjR_geDznNZuKR9du8tNl4p8wxTb6jJ9o"},
                    "client_id": {"cl_ra8t5tsberxpax0351jdyqgrb7"},
                    "resource": {"https://app.reflections.ai/mcp"},
                }
                body := strings.NewReader(form.Encode())
                request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/token", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
                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))
            }

  /oauth/register:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: createClient
      summary: Register a client
      x-mint:
        href: /api-reference/oauth/register-a-client
        metadata:
          playground: simple
      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.
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security:
        - {}
        - SecretKey: []
      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" }
      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))
            }

  /oauth/introspect:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: introspectToken
      summary: Introspect a token
      x-mint:
        href: /api-reference/oauth/introspect-a-token
        metadata:
          playground: simple
      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).

        Tells a content host whether an RSL `License` token is active and whether it covers the
        content it was presented for, as OAuth Token Introspection (RFC 7662) and RSL's Open
        License Protocol define. Call it when a client sends `Authorization: License <token>`, and
        serve the content only when `active` and `permitted` are both `true`.

        A token is inactive once it expires, and from the moment the license it draws on is
        revoked or suspended. Cache an active result for at most 60 seconds. An inactive result
        carries only `active: false`, whatever the reason. Only `License` tokens can be
        introspected: an MCP access token always reads as inactive here.

        Authenticate with a confidential client's client ID and secret, registered with
        [`POST /oauth/register`](/api-reference/oauth/register-a-client).
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security:
        - ClientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema: { $ref: "#/components/schemas/TokenIntrospectionCreate" }
            examples:
              license_token:
                summary: A content host checks a License token
                value:
                  token: rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV
                  resource: https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk
      responses:
        "200":
          description: Whether the token is active, and what it covers.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/TokenIntrospection" }
              examples:
                active:
                  summary: An active License token
                  value:
                    active: true
                    token_type: License
                    permitted: true
                    client_id: cl_zsyaax01q26b0kmq66g7wt70x9
                    resource: https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                    usage: [ai-input]
                    talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                    license: lic_j2fseppybf012bsxt93pv9y4b9
                    livemode: true
                    iat: 1792312320
                    exp: 1792398720
                inactive:
                  summary: An expired, revoked or unknown token
                  value:
                    active: false
        "400":
          description: "`token` is missing. `error` is `invalid_request`."
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/OAuthError" }
              example:
                error: invalid_request
                error_description: token is required.
        "401":
          description: The client ID or secret is wrong. `error` is `invalid_client`.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/OAuthError" }
              example:
                error: invalid_client
                error_description: Client authentication failed.
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            : "${REFLECTIONS_CLIENT_ID:?Set REFLECTIONS_CLIENT_ID before running this example}"
            : "${REFLECTIONS_CLIENT_SECRET:?Set REFLECTIONS_CLIENT_SECRET before running this example}"

            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/introspect' \
              -u "$REFLECTIONS_CLIENT_ID:$REFLECTIONS_CLIENT_SECRET" \
              -H "Content-Type: application/x-www-form-urlencoded" \
              --data-urlencode 'token=rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV' \
              --data-urlencode 'resource=https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk'
        - lang: typescript
          label: TypeScript
          source: |
            import { env, exit } from "node:process";
            import { Buffer } from "node:buffer";

            const clientId = env.REFLECTIONS_CLIENT_ID;
            if (!clientId) throw new Error("Set REFLECTIONS_CLIENT_ID before running this example");
            const clientSecret = env.REFLECTIONS_CLIENT_SECRET;
            if (!clientSecret) throw new Error("Set REFLECTIONS_CLIENT_SECRET before running this example");

            const response = await fetch("https://app.reflections.ai/oauth/introspect", {
              method: "POST",
              headers: {
                Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
                "Content-Type": "application/x-www-form-urlencoded",
              },
              body: new URLSearchParams({
                "token": "rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV",
                "resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk"
              }),
              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 base64
            import os
            from urllib.error import HTTPError
            from urllib.parse import urlencode
            from urllib.request import Request, urlopen

            clientId = os.environ["REFLECTIONS_CLIENT_ID"]
            if not clientId:
                raise ValueError("Set REFLECTIONS_CLIENT_ID before running this example")
            clientSecret = os.environ["REFLECTIONS_CLIENT_SECRET"]
            if not clientSecret:
                raise ValueError("Set REFLECTIONS_CLIENT_SECRET before running this example")

            headers = {
                "Authorization": "Basic " + base64.b64encode(f"{clientId}:{clientSecret}".encode()).decode(),
                "Content-Type": "application/x-www-form-urlencoded",
            }
            data = urlencode({
                "token": "rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV",
                "resource": "https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/oauth/introspect",
                              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"
                "net/url"
                "os"
                "strings"
                "time"
            )

            func main() {
                clientId := os.Getenv("REFLECTIONS_CLIENT_ID")
                if clientId == "" {
                    panic("Set REFLECTIONS_CLIENT_ID before running this example")
                }
                clientSecret := os.Getenv("REFLECTIONS_CLIENT_SECRET")
                if clientSecret == "" {
                    panic("Set REFLECTIONS_CLIENT_SECRET before running this example")
                }

                form := url.Values{
                    "token": {"rlt_vSJ3bKIxXFSmOQpwEb0SZrAhc4eOBrwV"},
                    "resource": {"https://app.reflections.ai/fct_5zba2q8v1m3n7p4r6s9t0wxyhk"},
                }
                body := strings.NewReader(form.Encode())
                request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/introspect", body)
                if err != nil {
                    panic(err)
                }
                request.SetBasicAuth(clientId, clientSecret)
                request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
                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))
            }

  /oauth/revoke:
    post:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: revokeToken
      summary: Revoke a token
      x-mint:
        href: /api-reference/oauth/revoke-a-token
        metadata:
          playground: simple
      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).

        Revokes an access or refresh token, as OAuth Token Revocation (RFC 7009) defines. Call it
        when the person signs out of your client. Revoking a refresh token also revokes every
        access token issued from it. The response is `200` whether or not the token was valid, so
        a retry is always safe.

        A person can also remove a client from their account settings, which revokes its tokens at
        once.

        Revocation takes no key. A public client sends its `client_id` in the body; a confidential
        client authenticates with its client ID and secret.
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security:
        - {}
        - ClientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema: { $ref: "#/components/schemas/TokenRevocationCreate" }
            examples:
              sign_out:
                summary: An MCP client signs out
                value:
                  token: rrt_Hq2Lw7Vb4Nc9Xk1Mz6Tr3Ys8Pd5Gf0Aj
                  token_type_hint: refresh_token
                  client_id: cl_ra8t5tsberxpax0351jdyqgrb7
      responses:
        "200":
          description: The token is revoked, or was not valid. The body is empty.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
        "400":
          description: "`token` is missing. `error` is `invalid_request`."
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/OAuthError" }
              example:
                error: invalid_request
                error_description: token is required.
        "401":
          description: The client ID or secret is wrong. `error` is `invalid_client`.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/OAuthError" }
              example:
                error: invalid_client
                error_description: Client authentication failed.
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            curl --fail-with-body --max-time 30 -X POST 'https://app.reflections.ai/oauth/revoke' \
              -H "Content-Type: application/x-www-form-urlencoded" \
              --data-urlencode 'token=rrt_Hq2Lw7Vb4Nc9Xk1Mz6Tr3Ys8Pd5Gf0Aj' \
              --data-urlencode 'token_type_hint=refresh_token' \
              --data-urlencode 'client_id=cl_ra8t5tsberxpax0351jdyqgrb7'
        - lang: typescript
          label: TypeScript
          source: |
            import { exit } from "node:process";

            const response = await fetch("https://app.reflections.ai/oauth/revoke", {
              method: "POST",
              headers: {
                "Content-Type": "application/x-www-form-urlencoded",
              },
              body: new URLSearchParams({
                "token": "rrt_Hq2Lw7Vb4Nc9Xk1Mz6Tr3Ys8Pd5Gf0Aj",
                "token_type_hint": "refresh_token",
                "client_id": "cl_ra8t5tsberxpax0351jdyqgrb7"
              }),
              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: |
            from urllib.error import HTTPError
            from urllib.parse import urlencode
            from urllib.request import Request, urlopen

            headers = {
                "Content-Type": "application/x-www-form-urlencoded",
            }
            data = urlencode({
                "token": "rrt_Hq2Lw7Vb4Nc9Xk1Mz6Tr3Ys8Pd5Gf0Aj",
                "token_type_hint": "refresh_token",
                "client_id": "cl_ra8t5tsberxpax0351jdyqgrb7",
            }).encode("utf-8")
            request = Request("https://app.reflections.ai/oauth/revoke",
                              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"
                "net/url"
                "strings"
                "time"
            )

            func main() {
                form := url.Values{
                    "token": {"rrt_Hq2Lw7Vb4Nc9Xk1Mz6Tr3Ys8Pd5Gf0Aj"},
                    "token_type_hint": {"refresh_token"},
                    "client_id": {"cl_ra8t5tsberxpax0351jdyqgrb7"},
                }
                body := strings.NewReader(form.Encode())
                request, err := http.NewRequest("POST", "https://app.reflections.ai/oauth/revoke", body)
                if err != nil {
                    panic(err)
                }
                request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
                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))
            }

  /.well-known/oauth-authorization-server:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveAuthorizationServerMetadata
      summary: Retrieve the authorization server metadata
      x-mint:
        href: /api-reference/oauth/retrieve-the-authorization-server-metadata
        metadata:
          playground: simple
      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).

        Describes the OAuth endpoints, grants and scopes, as OAuth Authorization Server Metadata
        (RFC 8414) defines. MCP clients and OAuth libraries read it instead of hard-coding URLs.
        Public, and served with `Cache-Control: public, max-age=3600`.
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security: []
      responses:
        "200":
          description: The authorization server metadata.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/AuthorizationServerMetadata" }
              examples:
                reflections: { $ref: "#/components/examples/AuthorizationServerMetadata" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            curl --fail-with-body --max-time 30 'https://app.reflections.ai/.well-known/oauth-authorization-server'
        - lang: typescript
          label: TypeScript
          source: |
            import { exit } from "node:process";

            const response = await fetch("https://app.reflections.ai/.well-known/oauth-authorization-server", {
              method: "GET",
              headers: {
              },
              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: |
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            headers = {
            }
            request = Request("https://app.reflections.ai/.well-known/oauth-authorization-server",
                              method="GET", headers=headers)
            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"
                "time"
            )

            func main() {
                request, err := http.NewRequest("GET", "https://app.reflections.ai/.well-known/oauth-authorization-server", nil)
                if err != nil {
                    panic(err)
                }
                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))
            }

  /.well-known/oauth-protected-resource/mcp:
    get:
      x-reflections-availability: { test: planned, live: unavailable }
      operationId: retrieveProtectedResourceMetadata
      summary: Retrieve the MCP server's resource metadata
      x-mint:
        href: /api-reference/oauth/retrieve-the-mcp-servers-resource-metadata
        metadata:
          playground: simple
      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).

        Describes the [MCP server](/api-reference/mcp/overview) as an OAuth protected resource, as
        RFC 9728 defines: which authorization server issues its tokens and which scopes it accepts.
        A request to `https://app.reflections.ai/mcp` without a valid token gets `401` with a
        `WWW-Authenticate` header whose `resource_metadata` points here. Public, and served with
        `Cache-Control: public, max-age=3600`.
      tags: [OAuth]
      servers:
        - url: https://app.reflections.ai
      security: []
      responses:
        "200":
          description: The protected resource metadata.
          headers:
            Request-Id: { $ref: "#/components/headers/RequestId" }
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ProtectedResourceMetadata" }
              examples:
                mcp: { $ref: "#/components/examples/ProtectedResourceMetadata" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
        "503": { $ref: "#/components/responses/Unavailable" }
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |
            curl --fail-with-body --max-time 30 'https://app.reflections.ai/.well-known/oauth-protected-resource/mcp'
        - lang: typescript
          label: TypeScript
          source: |
            import { exit } from "node:process";

            const response = await fetch("https://app.reflections.ai/.well-known/oauth-protected-resource/mcp", {
              method: "GET",
              headers: {
              },
              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: |
            from urllib.error import HTTPError
            from urllib.request import Request, urlopen

            headers = {
            }
            request = Request("https://app.reflections.ai/.well-known/oauth-protected-resource/mcp",
                              method="GET", headers=headers)
            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"
                "time"
            )

            func main() {
                request, err := http.NewRequest("GET", "https://app.reflections.ai/.well-known/oauth-protected-resource/mcp", nil)
                if err != nil {
                    panic(err)
                }
                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))
            }

webhooks:
  license.issued:
    post:
      operationId: webhookLicenseIssued
      summary: license.issued
      description: |
        The talent's side signed a new license for the licensee. It is `pending_acceptance` until the licensee accepts it on the hosted acceptance page. Checks against it return `license_pending_acceptance` until then.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_issued:
                summary: Maya Okafor signed a license for Ridgeline
                value:
                  id: evt_yjy0cs3br1aht5bv03zcah6bj5
                  object: event
                  type: license.issued
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-09-27T11:15:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: pending_acceptance
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: null
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: https://app.reflections.ai/l/K7Q4M2/accept
                      accepted_at: null
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.accepted:
    post:
      operationId: webhookLicenseAccepted
      summary: license.accepted
      description: |
        The licensee accepted a license. Checks may now allow uses within its scope from `starts_at`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_accepted:
                summary: Ridgeline accepted before the window started
                value:
                  id: evt_w5c468hz2maswzkghhnjfvxzzc
                  object: event
                  type: license.accepted
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-09-28T16:02:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: scheduled
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: null
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: null
                      accepted_at: "2026-09-28T16:02:00Z"
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
                    previous_attributes:
                      status: pending_acceptance
                      acceptance_url: https://app.reflections.ai/l/K7Q4M2/accept
                      accepted_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.revised:
    post:
      operationId: webhookLicenseRevised
      summary: license.revised
      description: |
        The licensee accepted a new revision. `current_revision` points at it. New checks use it at once; authorizations already issued keep the revision they name.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_revised:
                summary: Ridgeline accepted the revision that adds TV
                value:
                  id: evt_k78pyttbz09kftd4p32nnh97ae
                  object: event
                  type: license.revised
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 8
                  created_at: "2026-10-21T13:05:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: active
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_5ecwa673wbbej5a0zkz2vxnk49
                      revision_number: 3
                      pending_revision: null
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                          - tv
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: null
                      accepted_at: "2026-09-28T16:02:00Z"
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
                    previous_attributes:
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: lrv_5ecwa673wbbej5a0zkz2vxnk49
                      acceptance_url: https://app.reflections.ai/l/K7Q4M2/accept
                      scope:
                        channels:
                          - social
                          - web
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.revision_pending:
    post:
      operationId: webhookLicenseRevisionPending
      summary: license.revision_pending
      description: |
        The talent's side signed a new revision of a license: a change the licensee requested, an amendment or a renewal. `pending_revision` names it. The licensee accepts or declines it at `acceptance_url`; until it accepts, `current_revision` stays in force and checks use it.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              revision_pending:
                summary: A signed change adding TV waits for Ridgeline
                value:
                  id: evt_1fmn4f5cf233c9etd3f0s7sbhb
                  object: event
                  type: license.revision_pending
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 7
                  created_at: "2026-10-20T15:30:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: active
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: lrv_5ecwa673wbbej5a0zkz2vxnk49
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: https://app.reflections.ai/l/K7Q4M2/accept
                      accepted_at: "2026-09-28T16:02:00Z"
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
                    previous_attributes:
                      pending_revision: null
                      acceptance_url: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.revision_declined:
    post:
      operationId: webhookLicenseRevisionDeclined
      summary: license.revision_declined
      description: |
        The licensee declined a pending revision. `pending_revision` is `null` again and the license keeps its current revision. `previous_attributes.pending_revision` names the declined revision.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              revision_declined:
                summary: Ridgeline declined an amendment
                value:
                  id: evt_113h46xbrysjkdym54d5xhq604
                  object: event
                  type: license.revision_declined
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 6
                  created_at: "2026-10-19T09:45:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: active
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: null
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: null
                      accepted_at: "2026-09-28T16:02:00Z"
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
                    previous_attributes:
                      pending_revision: lrv_p89j65tg7m6zby4b3pt3rd6dmh
                      acceptance_url: https://app.reflections.ai/l/K7Q4M2/accept
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.suspended:
    post:
      operationId: webhookLicenseSuspended
      summary: license.suspended
      description: |
        The talent or a representative paused the license. Until `license.resumed`, checks deny with `license_suspended`, open sessions under it end with `session.terminated` and renewals fail with `409 session_not_active`; drop cached decisions under it. Held outputs stay held, and released outputs are unaffected. A suspension is not a revocation: it creates no revocation and needs no acknowledgement.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_suspended:
                summary: A representative paused the license
                value:
                  id: evt_xx57d6fyk5ngjbab9tqvhjgnyc
                  object: event
                  type: license.suspended
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 3
                  created_at: "2026-10-08T15:40:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: suspended
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: null
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: null
                      accepted_at: "2026-09-28T16:02:00Z"
                      suspended_at: "2026-10-08T15:40:00Z"
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
                    previous_attributes:
                      status: active
                      suspended_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.resumed:
    post:
      operationId: webhookLicenseResumed
      summary: license.resumed
      description: |
        A suspended license is active again.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_resumed:
                summary: The license is active again
                value:
                  id: evt_1qyf93zez4h92p5t5s77wt8e1n
                  object: event
                  type: license.resumed
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 4
                  created_at: "2026-10-09T10:05:01Z"
                  data:
                    object:
                      id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      object: license
                      livemode: true
                      status: active
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: K7Q4M2
                      current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      revision_number: 1
                      pending_revision: null
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      acceptance_url: null
                      accepted_at: "2026-09-28T16:02:00Z"
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-27T11:15:00Z"
                    previous_attributes:
                      status: suspended
                      suspended_at: "2026-10-08T15:40:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.revoked:
    post:
      operationId: webhookLicenseRevoked
      summary: license.revoked
      description: |
        The license was revoked. A `revocation.created` event with the actions you must take is sent at the same time; act on that one.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_revoked:
                summary: Maya Okafor revoked Northlight's voice license
                value:
                  id: evt_bv4wvxdavtz4ny842d7121tp69
                  object: event
                  type: license.revoked
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 3
                  created_at: "2026-10-17T18:03:41Z"
                  data:
                    object:
                      id: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                      object: license
                      livemode: true
                      status: revoked
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      issued_by:
                        party: talent
                        account: null
                      handle: V6R2T9
                      current_revision: lrv_7p4r6s9t0wxyhk5zba2q8v1m3n
                      revision_number: 1
                      pending_revision: null
                      scope:
                        facets:
                          - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                        modalities:
                          - speech
                        kinds:
                          - impersonation
                        purposes:
                          - personal
                          - branded_content
                        commercial: true
                        channels:
                          - in_app
                          - audio
                          - web
                        territories:
                          - US
                        window:
                          starts_at: "2026-09-02T00:00:00Z"
                          ends_at: "2027-06-30T23:59:59Z"
                          time_zone: null
                        required_attributes:
                          - identity.samePerson
                        release_policy: after_checks
                        escalation_window: P7D
                        final_deliverables: null
                        monthly_limits:
                          seconds: 100000
                        sessions:
                          permitted: true
                          sampling:
                            audio_window_max: PT15S
                            transcript: every_turn
                        material_access: []
                        platforms:
                          mode: listed
                          accounts:
                            - acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                        sublicense: end_users_personal
                        training: prohibited
                        disclosure: licensed
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: seconds
                            rate:
                              amount: 2
                              currency: usd
                            per: 1
                          schedule: monthly
                      acceptance_url: null
                      accepted_at: "2026-09-01T16:45:00Z"
                      suspended_at: null
                      revoked_at: "2026-10-17T18:03:40Z"
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-01T10:00:00Z"
                    previous_attributes:
                      status: active
                      revoked_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.expired:
    post:
      operationId: webhookLicenseExpired
      summary: license.expired
      description: |
        The license window ended. Checks deny with `window_ended`. Outputs released under it may no longer be placed, and their receipts report `use_status: expired`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_expired:
                summary: A one-month retail license ended
                value:
                  id: evt_1tfhsgeph25hrefqrz55c6tbk3
                  object: event
                  type: license.expired
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 3
                  created_at: "2026-10-10T04:00:01Z"
                  data:
                    object:
                      id: lic_2xzg3abqbz7fxf5qeaq2fa4d81
                      object: license
                      livemode: true
                      status: expired
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: talent
                        account: null
                      handle: B8F3N6
                      current_revision: lrv_121efjq4smbppc2gcwjpj9cmy2
                      revision_number: 1
                      pending_revision: null
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - retail
                          - out_of_home
                        territories:
                          - US
                        window:
                          starts_at: "2026-09-10T04:00:00Z"
                          ends_at: "2026-10-10T04:00:00Z"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: after_checks
                        escalation_window: P3D
                        final_deliverables: 6
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: licensed
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: flat
                          flat:
                            amount: 1200000
                            currency: usd
                          schedule: on_acceptance
                      acceptance_url: null
                      accepted_at: "2026-09-04T10:30:00Z"
                      suspended_at: null
                      revoked_at: null
                      declined_at: null
                      metadata: {}
                      created_at: "2026-09-03T13:00:00Z"
                    previous_attributes:
                      status: active
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license.declined:
    post:
      operationId: webhookLicenseDeclined
      summary: license.declined
      description: |
        The licensee declined a license before accepting it.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseEvent" }
            examples:
              license_declined:
                summary: Ridgeline declined a video license
                value:
                  id: evt_7kfp4p8wfnebcyw1ak3saxz5by
                  object: event
                  type: license.declined
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-14T11:20:01Z"
                  data:
                    object:
                      id: lic_p9kcy2ze131s79zp3tgwp41fd1
                      object: license
                      livemode: true
                      status: declined
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      issued_by:
                        party: representative
                        account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                        mandate: mnd_7nb1ef0wykcj3mkwaba3x20ez6
                        draft: ldr_2j71dr2g5hstydgtw8mv1frhps
                      handle: M5W9C2
                      current_revision: lrv_7xv40p4f4a84npwm67t45r85v7
                      revision_number: 1
                      pending_revision: null
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - video
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                        territories:
                          - US
                        window:
                          starts_at: "2026-11-01T04:00:00Z"
                          ends_at: "2027-02-01T05:00:00Z"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                            - "No dialogue: she does not speak on camera."
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 4
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: flat
                          flat:
                            amount: 3000000
                            currency: usd
                          schedule: on_acceptance
                      acceptance_url: null
                      accepted_at: null
                      suspended_at: null
                      revoked_at: null
                      declined_at: "2026-10-14T11:20:00Z"
                      metadata: {}
                      created_at: "2026-10-12T17:00:00Z"
                    previous_attributes:
                      status: pending_acceptance
                      acceptance_url: https://app.reflections.ai/l/M5W9C2/accept
                      declined_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license_request.signed:
    post:
      operationId: webhookLicenseRequestSigned
      summary: license_request.signed
      description: |
        The talent's side signed a license from your request. `license_revision` names what they signed, which may differ from what you asked. `license.issued` follows for a new license, or `license.revision_pending` for a change.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseRequestEvent" }
            examples:
              request_signed:
                summary: Maya Okafor signed the TV change, with fewer outputs
                value:
                  id: evt_3dpyn4tskqeevbb431hxt7rxmk
                  object: event
                  type: license_request.signed
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-20T15:30:01Z"
                  data:
                    object:
                      id: lrq_py3xqfvbjjcdhvf33y6c2w26jm
                      object: license_request
                      livemode: true
                      kind: change
                      status: signed
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      license_revision: lrv_5ecwa673wbbej5a0zkz2vxnk49
                      check: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
                      requested_scope:
                        channels:
                          - social
                          - web
                          - tv
                        final_deliverables: 30
                      offer:
                        type: flat
                        flat:
                          amount: 1000000
                          currency: usd
                        schedule: on_acceptance
                      note: We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.
                      decision_note: TV is approved. The total stays at 24 final outputs.
                      signed_at: "2026-10-20T15:30:00Z"
                      declined_at: null
                      withdrawn_at: null
                      metadata:
                        campaign: trail-winter-tv
                      created_at: "2026-10-17T18:10:00Z"
                    previous_attributes:
                      status: sent
                      license_revision: null
                      decision_note: null
                      signed_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license_request.declined:
    post:
      operationId: webhookLicenseRequestDeclined
      summary: license_request.declined
      description: |
        The talent's side declined your request. `decision_note` holds their note, if they wrote one.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseRequestEvent" }
            examples:
              request_declined:
                summary: The talent's manager declined a voice request
                value:
                  id: evt_56skvqwdtkrh913mg21ewgkwyj
                  object: event
                  type: license_request.declined
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-16T12:30:01Z"
                  data:
                    object:
                      id: lrq_dp9594v61t1wk0mebf6t7dpyae
                      object: license_request
                      livemode: true
                      kind: new
                      status: declined
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      license: null
                      license_revision: null
                      check: null
                      requested_scope:
                        facet_types:
                          - voice
                        modalities:
                          - speech
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - audio
                          - streaming
                        territories:
                          - US
                        starts_at: "2026-11-01T04:00:00Z"
                        ends_at: "2027-02-01T05:00:00Z"
                        final_deliverables: 2
                      offer:
                        type: flat
                        flat:
                          amount: 2000000
                          currency: usd
                        schedule: on_acceptance
                      note: Two 30-second radio and streaming spots for the winter campaign, read in Maya's voice.
                      decision_note: Maya is not licensing her voice for advertising.
                      signed_at: null
                      declined_at: "2026-10-16T12:30:00Z"
                      withdrawn_at: null
                      metadata: {}
                      created_at: "2026-10-14T16:00:00Z"
                    previous_attributes:
                      status: sent
                      decision_note: null
                      declined_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  check.resolved:
    post:
      operationId: webhookCheckResolved
      summary: check.resolved
      description: |
        An escalated check was decided or expired. If `decision` is `allow`, its authorization now covers exactly the request you escalated, bound by `request_digest`. If `deny`, `reasons` say why; an expired escalation carries `hold_expired`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/CheckEvent" }
            examples:
              allowed:
                summary: A reviewer allowed an escalated check
                value:
                  id: evt_r95tsmb9qgkm4aavg2evx6qhss
                  object: event
                  type: check.resolved
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 2
                  created_at: "2026-10-20T14:12:01Z"
                  data:
                    object:
                      id: chk_3pg20xkepkscyp0qbpc4yq7ad2
                      object: check
                      livemode: true
                      status: allowed
                      decision: allow
                      talent:
                        - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          name: Maya Okafor
                          matched_by: name
                          confidence: high
                          decision: allow
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                          license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                          terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                          escalation: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                      use:
                        modality: image
                        kind: depiction
                        purpose: advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                      reasons: []
                      obligations:
                        - type: generation_check
                          required: all
                        - type: hold_until_release
                          reviewer: talent
                        - type: draft_watermark
                        - type: generation_instructions
                          instructions:
                            - "Keep Maya Okafor the same person: face, skin tone and build unchanged."
                            - Do not show alcohol or tobacco.
                            - Do not imply she endorses any product other than the one shown.
                          term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                        - type: disclosure
                          level: brand
                          placement: both
                          text: Made with AI. Maya Okafor's likeness used under license by Ridgeline.
                        - type: c2pa_manifest
                        - type: no_training
                          material: outputs
                        - type: usage_report
                          units: placements
                          within: P30D
                      authorization:
                        token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLWF1dGgrand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwOTAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoiY2hrXzNtN3A0cjZzOXQwd3h5aGs1emJhMnE4djFuIiwic3ViIjoiYWNjdF8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJkZWNpc2lvbiI6ImFsbG93IiwiZXUiOiIzZjljMWE3ZTViMmQ4ZjQwNjFjM2U5YTdiNWQyZjgwMTZlNGM5YTNiN2QxZjVlMmM4YTZiNGQwZjllM2M3YTE1IiwiZXhlY3V0aW9uIjp7Im1vZGVsIjoiaW1hZ2UtbW9kZWwtMyIsInByb3ZpZGVyIjoiZXhhbXBsZS1pbWFnZS1wcm92aWRlciJ9LCJmYWNldHMiOlsiZmN0XzV6YmEycTh2MW0zbjdwNHI2czl0MHd4eWhrIl0sImxpY2Vuc2VzIjpbeyJsaWNlbnNlIjoibGljX2s1emJhMnE4djFtM243cDRyNnM5dDB3eHloIiwicmV2aXNpb24iOiJscnZfcDRyNnM5dDB3eHloazV6YmEycTh2MW0zbjciLCJ0YWxlbnQiOiJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiLCJ0ZXJtc19kaWdlc3QiOiJzaGEyNTY6MzlmMThjOGJlZjAyYjUyMjZiOWZlYWE5MmU1MjZlZDMwYjgxYjkxNjUwZDhhMTBiNTAzMjgxYjE2OWY0NDQzMSJ9XSwibWF4X2dlbmVyYXRpb25zIjo0LCJvYmxpZ2F0aW9ucyI6WyJnZW5lcmF0aW9uX2NoZWNrIiwiaG9sZF91bnRpbF9yZWxlYXNlIiwiZHJhZnRfd2F0ZXJtYXJrIiwiZ2VuZXJhdGlvbl9pbnN0cnVjdGlvbnMiLCJkaXNjbG9zdXJlIiwiYzJwYV9tYW5pZmVzdCIsIm5vX3RyYWluaW5nIiwidXNhZ2VfcmVwb3J0Il0sInJlcXVlc3RfZGlnZXN0Ijoic2hhMjU2OmJmOTQ4MTc3NjZkNTZkOTIyMTFkMTJmNWZmNTFhM2RjMWE2ZDVjYjRiZTI4Nzc0MTdiMDgyNTFmZTM4YzM4NmEiLCJ0YWxlbnQiOlsidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIl0sInVzZSI6eyJjaGFubmVscyI6WyJzb2NpYWwiLCJ3ZWIiXSwiY29tbWVyY2lhbCI6dHJ1ZSwia2luZCI6ImRlcGljdGlvbiIsIm1vZGFsaXR5IjoiaW1hZ2UiLCJwdXJwb3NlIjoiYWR2ZXJ0aXNpbmciLCJ0ZXJyaXRvcmllcyI6WyJVUyIsIkNBIl19LCJ2ZXIiOiIxLjAifX0.sbcXipODRBifCQEGJacDUoBBDzW1YzLdbKAv-ky0fZXjfGRTx4JQd2nap26LYy7PlMRod-7rfqLFgmWE4tutdg
                        max_generations: 4
                        generations_used: 0
                        expires_at: "2026-10-20T14:27:00Z"
                      escalation:
                        id: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                        reason: evaluation_unavailable
                        reviewer: talent
                        status: allowed
                        expires_at: "2026-10-27T09:41:00Z"
                        resolved_at: "2026-10-20T14:12:00Z"
                        note: Approved for the fall campaign.
                      remedy: null
                      request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      session: null
                      receipt: rcpt_hn7bre4e4qpjse60cjecdh49yb
                      metadata: {}
                      created_at: "2026-10-20T09:41:00Z"
                    previous_attributes:
                      status: escalated
                      decision: escalate
                      talent:
                        - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          name: Maya Okafor
                          matched_by: name
                          confidence: high
                          decision: escalate
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                          license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                          terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                          escalation: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                      reasons:
                        - code: evaluation_unavailable
                          stage: check
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          sentence: This request could not be checked in time, so Maya Okafor's side will review it.
                      obligations: []
                      authorization: null
                      escalation:
                        id: esc_7nr5ftgs8c3aqh9w2fbp0sbdw7
                        reason: evaluation_unavailable
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-27T09:41:00Z"
                        resolved_at: null
                        note: null
                      receipt: null
              expired:
                summary: An escalation nobody answered in time
                value:
                  id: evt_xsg4refsj7224ezq3kq14ztv46
                  object: event
                  type: check.resolved
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 2
                  created_at: "2026-10-16T15:20:01Z"
                  data:
                    object:
                      id: chk_3zdxq6ypwsk2bcq7jkh34tsnhg
                      object: check
                      livemode: true
                      status: denied
                      decision: deny
                      talent:
                        - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          name: Maya Okafor
                          matched_by: name
                          confidence: high
                          decision: deny
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                          license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                          terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                          escalation: esc_sctm18fnpfhmjp050cxksjtv49
                      use:
                        modality: image
                        kind: depiction
                        purpose: advertising
                        commercial: true
                        channels:
                          - social
                        territories:
                          - US
                      reasons:
                        - code: hold_expired
                          stage: check
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          sentence: Maya Okafor's side did not answer this request before it expired.
                      obligations: []
                      authorization: null
                      escalation:
                        id: esc_sctm18fnpfhmjp050cxksjtv49
                        reason: evaluation_unavailable
                        reviewer: talent
                        status: expired
                        expires_at: "2026-10-16T15:20:00Z"
                        resolved_at: "2026-10-16T15:20:00Z"
                        note: null
                      remedy: null
                      request_digest: sha256:9c9734392354b42eab8af1a44c182d57efe13d259f57a5ebf826c3e4b87fe4ff
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      session: null
                      receipt: rcpt_0p7yj3wa9sta2rzfwykd44ft8w
                      metadata: {}
                      created_at: "2026-10-09T15:20:00Z"
                    previous_attributes:
                      status: escalated
                      decision: escalate
                      talent:
                        - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          name: Maya Okafor
                          matched_by: name
                          confidence: high
                          decision: escalate
                          facets:
                            - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                          license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                          terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                          escalation: esc_sctm18fnpfhmjp050cxksjtv49
                      reasons:
                        - code: evaluation_unavailable
                          stage: check
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          sentence: This request could not be checked in time, so Maya Okafor's side will review it.
                      escalation:
                        id: esc_sctm18fnpfhmjp050cxksjtv49
                        reason: evaluation_unavailable
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-16T15:20:00Z"
                        resolved_at: null
                        note: null
                      receipt: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  generation.allowed:
    post:
      operationId: webhookGenerationAllowed
      summary: generation.allowed
      description: |
        An output that was still being checked, such as a video, is allowed. Embed the receipt and deliver.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenerationEvent" }
            examples:
              long_speech:
                summary: Speech over 60 seconds, allowed after checking
                value:
                  id: evt_nmyp4vzw5hw6j9nb4t2d2136zh
                  object: event
                  type: generation.allowed
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-16T16:40:41Z"
                  data:
                    object:
                      id: gen_9mmat1kxjxyasrp73aj2x45z64
                      object: generation
                      livemode: true
                      check: chk_p93nhgy64xysd46zjeyf94v4sj
                      session: null
                      candidate_index: 0
                      status: allowed
                      decision: allow
                      artifact:
                        file: file_amjk4n6hrzb4gj3zb5h1cpfyr6
                        sha256: 70be3645e199401c8e769baf7cd16484de64729015cd8894d320040fdeb6d732
                        media_type: audio/wav
                        duration_ms: 94200
                      execution:
                        provider: example-voice-provider
                        model: tts-2
                        job_id: job_90533
                      findings:
                        - term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.requiredAttributes
                          attribute: identity.samePerson
                          result: preserved
                        - term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                          rule: Do not discuss politics or religion.
                          result: preserved
                      unchecked_terms: []
                      reasons: []
                      obligations:
                        - type: disclosure
                          level: licensed
                          placement: metadata
                          text: AI voice of Maya Okafor, licensed.
                        - type: c2pa_manifest
                        - type: usage_report
                          units: seconds
                          within: P1D
                      escalation: null
                      assurance: observed
                      receipt: rcpt_qj4fzc9hjertkkf8fcx2a1edme
                      c2pa:
                        label: ai.reflections.license
                        data:
                          receipt: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg
                          verify_url: https://app.reflections.ai/r/rcpt_qj4fzc9hjertkkf8fcx2a1edme
                      watermark: null
                      metadata: {}
                      created_at: "2026-10-16T16:40:00Z"
                      decided_at: "2026-10-16T16:40:41Z"
                    previous_attributes:
                      status: checking
                      decision: null
                      findings: []
                      receipt: null
                      c2pa: null
                      decided_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  generation.released:
    post:
      operationId: webhookGenerationReleased
      summary: generation.released
      description: |
        A reviewer released a held output. You may now deliver the clean output. Embed the receipt first.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenerationEvent" }
            examples:
              released:
                summary: Maya Okafor released a held image
                value:
                  id: evt_8v1m3n7p4r6s9t0wxyhk5zba2q
                  object: event
                  type: generation.released
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 3
                  created_at: "2026-10-17T19:42:10Z"
                  data:
                    object:
                      id: gen_6s9t0wxyhk5zba2q8v1m3n7p4r
                      object: generation
                      livemode: true
                      check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                      session: null
                      candidate_index: 0
                      status: released
                      decision: allow
                      artifact:
                        file: file_2c4e6g8j0k2m4n6p8q0r2s4t6v
                        sha256: 9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a
                        media_type: image/png
                        duration_ms: null
                      execution:
                        provider: example-image-provider
                        model: image-model-3
                        job_id: job_88213
                      findings:
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                          attribute: identity.samePerson
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                          attribute: appearance.wardrobe
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                          rule: Do not show alcohol or tobacco.
                          result: preserved
                      unchecked_terms: []
                      reasons: []
                      obligations:
                        - type: disclosure
                          level: brand
                          placement: both
                          text: Made with AI. Maya Okafor's likeness used under license by Ridgeline.
                        - type: c2pa_manifest
                        - type: usage_report
                          units: placements
                          within: P30D
                      escalation:
                        id: esc_hk5zba2q8v1m3n7p4r6s9t0wxy
                        reason: release_review
                        reviewer: talent
                        status: allowed
                        expires_at: "2026-10-24T18:00:12Z"
                        resolved_at: "2026-10-17T19:42:09Z"
                        note: null
                      assurance: observed
                      receipt: rcpt_bfwgfkw4w683avvxm1q0h4fard
                      c2pa:
                        label: ai.reflections.license
                        data:
                          receipt: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg
                          verify_url: https://app.reflections.ai/r/rcpt_bfwgfkw4w683avvxm1q0h4fard
                      watermark: null
                      metadata: {}
                      created_at: "2026-10-17T18:00:12Z"
                      decided_at: "2026-10-17T19:42:09Z"
                    previous_attributes:
                      status: held
                      decision: escalate
                      obligations:
                        - type: hold_until_release
                          reviewer: talent
                        - type: draft_watermark
                      escalation:
                        id: esc_hk5zba2q8v1m3n7p4r6s9t0wxy
                        reason: release_review
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-24T18:00:12Z"
                        resolved_at: null
                        note: null
                      receipt: null
                      c2pa: null
                      decided_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  generation.denied:
    post:
      operationId: webhookGenerationDenied
      summary: generation.denied
      description: |
        An output was denied after an asynchronous check, a reviewer declined it, or a revocation ended a hold before release (`license_revoked`). Never deliver it. `reasons` say why.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenerationEvent" }
            examples:
              review_declined:
                summary: Maya Okafor declined a held image
                value:
                  id: evt_88cqw07r3qqakw0x9nv684kym6
                  object: event
                  type: generation.denied
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 3
                  created_at: "2026-10-17T19:44:30Z"
                  data:
                    object:
                      id: gen_27anw6frbr27snr28r4rtby65t
                      object: generation
                      livemode: true
                      check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
                      session: null
                      candidate_index: 3
                      status: denied
                      decision: deny
                      artifact:
                        file: file_qd3fjw5kzmxmsej34ccjbb3te2
                        sha256: 1f515e0ac5910efaf0ed6a4477f38775ad9dcc6ccb5070f421a0fe85d49867d7
                        media_type: image/png
                        duration_ms: null
                      execution:
                        provider: example-image-provider
                        model: image-model-3
                        job_id: job_88216
                      findings:
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                          attribute: identity.samePerson
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                          attribute: appearance.wardrobe
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                          rule: Do not show alcohol or tobacco.
                          result: preserved
                      unchecked_terms: []
                      reasons:
                        - code: review_declined
                          stage: generation
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          sentence: Maya Okafor declined this output.
                      obligations: []
                      escalation:
                        id: esc_fxr2jmbkavw2sqhgjp78qw9nt7
                        reason: release_review
                        reviewer: talent
                        status: denied
                        expires_at: "2026-10-24T18:04:10Z"
                        resolved_at: "2026-10-17T19:44:30Z"
                        note: The shoe is out of focus. Use one where it is sharp.
                      assurance: observed
                      receipt: rcpt_thhgzpyz5qx8v26nvyxpkpaewz
                      c2pa: null
                      watermark: null
                      metadata: {}
                      created_at: "2026-10-17T18:04:10Z"
                      decided_at: "2026-10-17T19:44:30Z"
                    previous_attributes:
                      status: held
                      decision: escalate
                      reasons: []
                      obligations:
                        - type: hold_until_release
                          reviewer: talent
                        - type: draft_watermark
                      escalation:
                        id: esc_fxr2jmbkavw2sqhgjp78qw9nt7
                        reason: release_review
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-24T18:04:10Z"
                        resolved_at: null
                        note: null
                      receipt: null
                      decided_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  generation.expired:
    post:
      operationId: webhookGenerationExpired
      summary: generation.expired
      description: |
        A held output was not reviewed within its window and can no longer be released.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GenerationEvent" }
            examples:
              review_expired:
                summary: A held image nobody released in 7 days
                value:
                  id: evt_nmwpaj3d3qpn2k006g58811gae
                  object: event
                  type: generation.expired
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 3
                  created_at: "2026-10-13T14:22:31Z"
                  data:
                    object:
                      id: gen_cdpgrnkdfkckevasexz7qs77p6
                      object: generation
                      livemode: true
                      check: chk_3cgv07hsb9q2ttqy2gve93xc3p
                      session: null
                      candidate_index: 0
                      status: expired
                      decision: deny
                      artifact:
                        file: file_pct6b9jjzpr9aft62vv4ykjn9n
                        sha256: add5be98c594560e8ef3ac5651c74d5a0be44d58827858c95dcabcbf817f6662
                        media_type: image/png
                        duration_ms: null
                      execution:
                        provider: example-image-provider
                        model: image-model-3
                        job_id: job_86032
                      findings:
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                          attribute: identity.samePerson
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                          attribute: appearance.wardrobe
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                          rule: Do not show alcohol or tobacco.
                          result: preserved
                      unchecked_terms: []
                      reasons:
                        - code: review_expired
                          stage: generation
                          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                          sentence: This output was not released before its review window closed.
                      obligations: []
                      escalation:
                        id: esc_h4mt5crpqgg4wevz29mfmxdh8k
                        reason: release_review
                        reviewer: talent
                        status: expired
                        expires_at: "2026-10-13T14:22:31Z"
                        resolved_at: "2026-10-13T14:22:31Z"
                        note: null
                      assurance: observed
                      receipt: rcpt_zzm3kgd3t1w0m58dapv7c17t90
                      c2pa: null
                      watermark: null
                      metadata: {}
                      created_at: "2026-10-06T14:22:31Z"
                      decided_at: "2026-10-13T14:22:31Z"
                    previous_attributes:
                      status: held
                      decision: escalate
                      reasons: []
                      obligations:
                        - type: hold_until_release
                          reviewer: talent
                        - type: draft_watermark
                      escalation:
                        id: esc_h4mt5crpqgg4wevz29mfmxdh8k
                        reason: release_review
                        reviewer: talent
                        status: open
                        expires_at: "2026-10-13T14:22:31Z"
                        resolved_at: null
                        note: null
                      receipt: null
                      decided_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  session.terminated:
    post:
      operationId: webhookSessionTerminated
      summary: session.terminated
      description: |
        Reflections ended a session: a sample was denied, the license was revoked or suspended, or renewal stopped. Stop output within one second. `data.object` is the session, and `data.object.termination` says why and when. The session stream pushes the same termination as a `session.terminated` message, usually sooner, with the reason's `sentence` and any `revocation` or `sample`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/SessionEvent" }
            examples:
              license_revoked:
                summary: A session ended by a revocation
                value:
                  id: evt_xj2af4kr0x0hnbgpwy1zc7c1yc
                  object: event
                  type: session.terminated
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-17T18:03:41Z"
                  data:
                    object:
                      id: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
                      object: session
                      livemode: true
                      status: terminated
                      check: chk_n7p4r6s9t0wxyhk5zba2q8v1m3
                      license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                      talent:
                        - tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      token: null
                      expires_at: null
                      renew_every: PT60S
                      sampling:
                        audio_window_max: PT15S
                        transcript: every_turn
                      obligations:
                        - type: disclosure
                          level: licensed
                          placement: visible
                          text: AI voice of Maya Okafor, licensed.
                        - type: generation_instructions
                          instructions:
                            - Do not discuss politics or religion.
                            - Do not make promises on her behalf.
                          term: license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never
                        - type: usage_report
                          units: seconds
                          within: P1D
                      reasons: []
                      stream_url: wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream
                      termination:
                        reason: license_revoked
                        sentence: Maya Okafor revoked this license.
                        revocation: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                        sample: null
                        at: "2026-10-17T18:03:41Z"
                      ended_at: null
                      metadata: {}
                      created_at: "2026-10-17T18:00:00Z"
                    previous_attributes:
                      status: active
                      token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXNlc3Npb24rand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwMzAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwic3ViIjoiYWNjdF83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRscCI6eyJjaGVjayI6ImNoa19uN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtMyIsImV1IjoiM2Y5YzFhN2U1YjJkOGY0MDYxYzNlOWE3YjVkMmY4MDE2ZTRjOWEzYjdkMWY1ZTJjOGE2YjRkMGY5ZTNjN2ExNSIsImZhY2V0cyI6WyJmY3RfdjFtM243cDRyNnM5dDB3eHloazV6YmEycTgiXSwibGljZW5zZXMiOlt7ImxpY2Vuc2UiOiJsaWNfYmEycTh2MW0zbjdwNHI2czl0MHd4eWhrNXoiLCJyZXZpc2lvbiI6Imxydl83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRhbGVudCI6InRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyIsInRlcm1zX2RpZ2VzdCI6InNoYTI1Njo4ZTBhMmM0ZTZiOGQwZjJhNGM2ZThiMGQyZjRhNmM4ZTBiMmQ0ZjZhOGMwZTJiNGQ2ZjhhMGMyZTRiNmQ4ZjBhIn1dLCJzYW1wbGluZyI6eyJhdWRpb193aW5kb3dfbWF4IjoiUFQxNVMiLCJ0cmFuc2NyaXB0IjoiZXZlcnlfdHVybiJ9LCJzZXNzaW9uIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwidGFsZW50IjpbInRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyJdLCJ1c2UiOnsiY2hhbm5lbHMiOlsiaW5fYXBwIl0sImNvbW1lcmNpYWwiOmZhbHNlLCJraW5kIjoiaW1wZXJzb25hdGlvbiIsIm1vZGFsaXR5Ijoic3BlZWNoIiwicHVycG9zZSI6InBlcnNvbmFsIiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.RD_dRcXCqGHhYvg-PV3b1JIAoAX-WzVp02x6j-eSzmhYFxuZvniuJVrhJuHmzlFq_FYr6smqYXHQzb5p8DI0gA
                      expires_at: "2026-10-17T18:08:00Z"
                      termination: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  revocation.created:
    post:
      operationId: webhookRevocationCreated
      summary: revocation.created
      description: |
        Consent narrowed: a license was revoked, a facet withdrawn, a mandate ended, or a talent withdrew consent. Stop generating under the targets, purge cached decisions, delete provider-held copies, apply `post_revocation` to released outputs, and acknowledge before `acknowledge_by`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/RevocationEvent" }
            examples:
              license_revoked:
                summary: A voice license revoked
                value:
                  id: evt_rx3mb5a2y3eww8gxax1wbnd2ek
                  object: event
                  type: revocation.created
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-10-17T18:03:42Z"
                  data:
                    object:
                      id: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
                      object: revocation
                      livemode: true
                      scope: license
                      targets:
                        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                        licenses:
                          - lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                        facets:
                          - fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                        mandate: null
                      status: pending_acknowledgement
                      initiated_by: talent
                      for_cause: false
                      cause: null
                      note: null
                      effective_at: "2026-10-17T18:03:40Z"
                      post_revocation:
                        policy: retain
                        withdraw_by: null
                      required_actions:
                        - stop_generation
                        - purge_cached_decisions
                        - delete_provider_copies
                      provider_copies:
                        - facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                          provider: example-voice-provider
                          external_id: vx_4f9a2c
                      affected:
                        checks_denied: 3
                        generations_denied: 0
                        sessions_terminated: 1
                        released_outputs: 418
                      acknowledge_by: "2026-10-18T18:03:40Z"
                      acknowledgements: []
                      created_at: "2026-10-17T18:03:40Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  revocation.overdue:
    post:
      operationId: webhookRevocationOverdue
      summary: revocation.overdue
      description: |
        A revocation passed a deadline before its actions were acknowledged: `acknowledge_by`, or `post_revocation.withdraw_by` for `withdraw_outputs`. It is now shown as overdue on the talent's record and to your account contact.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/RevocationEvent" }
            examples:
              withdrawal_overdue:
                summary: withdraw_outputs not acknowledged by withdraw_by
                value:
                  id: evt_8zx6m206b37q9g5y3y5z9gk8a2
                  object: event
                  type: revocation.overdue
                  api_version: "2026-10-15"
                  livemode: true
                  account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                  sequence: 2
                  created_at: "2026-10-09T15:20:01Z"
                  data:
                    object:
                      id: rvk_6z4ke43tnnk4h14drgv1tt82q1
                      object: revocation
                      livemode: true
                      scope: license
                      targets:
                        talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                        licenses:
                          - lic_zfjz8gb26kcd5ynj2tpb55e8bp
                        facets: []
                        mandate: null
                      status: overdue
                      initiated_by: talent
                      for_cause: true
                      cause: Outputs used outside the licensed territories.
                      note: null
                      effective_at: "2026-10-02T15:20:00Z"
                      post_revocation:
                        policy: withdraw
                        withdraw_by: "2026-10-09T15:20:00Z"
                      required_actions:
                        - stop_generation
                        - purge_cached_decisions
                        - withdraw_outputs
                      provider_copies: []
                      affected:
                        checks_denied: 0
                        generations_denied: 1
                        sessions_terminated: 0
                        released_outputs: 14
                      acknowledge_by: "2026-10-03T15:20:00Z"
                      acknowledgements:
                        - account: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                          actions:
                            - stop_generation
                            - purge_cached_decisions
                          deleted_copies: []
                          note: Generation stopped and caches purged. Takedowns are in progress.
                          acknowledged_at: "2026-10-02T15:34:51Z"
                      created_at: "2026-10-02T15:20:00Z"
                    previous_attributes:
                      status: pending_acknowledgement
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  connection.created:
    post:
      operationId: webhookConnectionCreated
      summary: connection.created
      description: |
        A licensee connected your platform. You may now send checks with `Reflections-Account` set to the licensee.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/ConnectionEvent" }
            examples:
              connection_created:
                summary: Ridgeline connected Northlight
                value:
                  id: evt_z77z2f3mrha6c3wvhbsb02vwbj
                  object: event
                  type: connection.created
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-09-29T10:12:01Z"
                  data:
                    object:
                      id: con_av0baahbfheftkzxqbkns02qwf
                      object: connection
                      livemode: true
                      status: active
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      licensee_name: Ridgeline
                      platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      platform_name: Northlight
                      scopes:
                        - files:write
                        - checks:write
                        - generations:write
                        - usage:write
                      licenses:
                        mode: all
                        ids: []
                      revoked_by: null
                      revoked_at: null
                      created_at: "2026-09-29T10:12:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  connection.revoked:
    post:
      operationId: webhookConnectionRevoked
      summary: connection.revoked
      description: |
        A connection ended. Checks for that licensee fail with `account_not_connected`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/ConnectionEvent" }
            examples:
              connection_revoked:
                summary: Ridgeline ended its connection with Northlight
                value:
                  id: evt_sbpx62wq5gyjanknaynzvxy1ny
                  object: event
                  type: connection.revoked
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-28T16:20:01Z"
                  data:
                    object:
                      id: con_av0baahbfheftkzxqbkns02qwf
                      object: connection
                      livemode: true
                      status: revoked
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      licensee_name: Ridgeline
                      platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      platform_name: Northlight
                      scopes:
                        - files:write
                        - checks:write
                        - generations:write
                        - usage:write
                      licenses:
                        mode: all
                        ids: []
                      revoked_by: licensee
                      revoked_at: "2026-10-28T16:20:00Z"
                      created_at: "2026-09-29T10:12:00Z"
                    previous_attributes:
                      status: active
                      revoked_by: null
                      revoked_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  facet.updated:
    post:
      operationId: webhookFacetUpdated
      summary: facet.updated
      description: |
        A facet changed: its material, its status or its provider bindings. Refresh anything you cached about it.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/FacetEvent" }
            examples:
              binding_deleted:
                summary: A provider copy of a voice was deleted
                value:
                  id: evt_d8h51kw4nmr2zyxrvp37zewp1e
                  object: event
                  type: facet.updated
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 3
                  created_at: "2026-10-17T18:09:20Z"
                  data:
                    object:
                      id: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                      object: facet
                      livemode: true
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      type: voice
                      label: Speaking voice
                      status: ready
                      modalities:
                        - speech
                      material:
                        items: 12
                        updated_at: "2026-09-20T10:00:00Z"
                      provider_bindings:
                        - provider: example-voice-provider
                          kind: voice
                          external_id: vx_4f9a2c
                          status: deleted
                      created_at: "2026-06-12T09:00:00Z"
                      updated_at: "2026-10-17T18:09:20Z"
                    previous_attributes:
                      provider_bindings:
                        - provider: example-voice-provider
                          kind: voice
                          external_id: vx_4f9a2c
                          status: active
                      updated_at: "2026-09-20T10:00:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  talent.updated:
    post:
      operationId: webhookTalentUpdated
      summary: talent.updated
      description: |
        A talent's names, aliases, posture or protection changed. Refresh your name index.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/TalentEvent" }
            examples:
              alias_added:
                summary: The talent confirmed a new alias
                value:
                  id: evt_w51ha1r2hkcvasasct9h3zewvj
                  object: event
                  type: talent.updated
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-01T12:00:01Z"
                  data:
                    object:
                      id: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      object: talent
                      livemode: true
                      name: Maya Okafor
                      aliases:
                        - Maya O.
                      status: active
                      verification:
                        verified: true
                        method: id_document
                        verified_at: "2026-06-11T09:30:00Z"
                      protection:
                        references: true
                        modalities:
                          - image
                          - video
                          - speech
                      posture:
                        default: license_required
                        accepts_requests: true
                        rules:
                          - purpose: political
                            declaration: prohibited
                          - kind: endorsement
                            purpose: advertising
                            declaration: license_required
                          - modality: text
                            kind: reference
                            declaration: allowed
                            obligations: []
                      representation:
                        - account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                          name: Summit Talent Management
                          role: manager
                          powers:
                            - issue_licenses
                            - review_outputs
                            - revoke
                            - receive_statements
                      facets:
                        - id: fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                          type: likeness
                          label: Studio likeness
                          status: ready
                        - id: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
                          type: voice
                          label: Speaking voice
                          status: ready
                        - id: fct_q4r6s9t0wxyhk5zba2q8v1m3n7
                          type: name
                          label: Name
                          status: ready
                      hcs_subject_id: null
                      profile_url: https://app.reflections.ai/t/maya-okafor
                      created_at: "2026-06-11T09:00:00Z"
                      updated_at: "2026-10-01T12:00:00Z"
                    previous_attributes:
                      aliases: []
                      updated_at: "2026-09-14T08:12:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  statement.issued:
    post:
      operationId: webhookStatementIssued
      summary: statement.issued
      description: |
        A monthly statement was issued for a license you hold.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/StatementEvent" }
            examples:
              issued:
                summary: A September statement, issued
                value:
                  id: evt_57qzqasftsgz69bb2gd6g8bsfm
                  object: event
                  type: statement.issued
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-10-02T08:00:01Z"
                  data:
                    object:
                      id: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                      object: statement
                      livemode: true
                      license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      status: issued
                      period:
                        start: "2026-09-01T00:00:00Z"
                        end: "2026-10-01T00:00:00Z"
                      currency: usd
                      lines:
                        - description: Speech in Maya Okafor's voice
                          units: seconds
                          reported: 41200
                          observed: 41236
                          billable: 41236
                          rate:
                            amount: 2
                            currency: usd
                          amount: 82472
                      amount_due: 82472
                      amount_paid: 0
                      reconciliation:
                        result: under_reported
                        detail: 36 seconds observed in generations with no usage record.
                      payments: []
                      due_at: "2026-10-31T00:00:00Z"
                      issued_at: "2026-10-02T08:00:00Z"
                      document_url: https://app.reflections.ai/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                      created_at: "2026-09-01T00:00:00Z"
                    previous_attributes:
                      status: open
                      due_at: null
                      issued_at: null
                      document_url: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  webhook_endpoint.disabled:
    post:
      operationId: webhookWebhookEndpointDisabled
      summary: webhook_endpoint.disabled
      description: |
        An endpoint failed for 5 days and was disabled. Fix it and re-enable it; read missed events with the events list.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/WebhookEndpointEvent" }
            examples:
              endpoint_disabled:
                summary: An endpoint disabled after 5 days of failures
                value:
                  id: evt_rtw0zjwwypdat4z2f1d578me44
                  object: event
                  type: webhook_endpoint.disabled
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-16T06:14:00Z"
                  data:
                    object:
                      id: we_y18vejcjn8vvdfs468q4fzhtb2
                      object: webhook_endpoint
                      livemode: true
                      url: https://northlight.example/webhooks/revocations
                      events:
                        - revocation.created
                        - revocation.overdue
                        - license.suspended
                        - license.resumed
                        - license.revoked
                      description: Revocation worker
                      status: disabled
                      disabled_reason: Every delivery failed for 5 days. The last attempt timed out after 10 seconds.
                      api_version: "2026-10-15"
                      connected: true
                      secret: null
                      metadata:
                        team: trust-and-safety
                      created_at: "2026-09-14T10:30:00Z"
                    previous_attributes:
                      status: enabled
                      disabled_reason: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license_request.created:
    post:
      operationId: webhookLicenseRequestCreated
      summary: license_request.created
      description: |
        A licensee asked a talent you represent for a license, or for a wider one. Sent to representatives whose mandate has `issue_licenses`. Answer with a [license draft](/api-reference/license-drafts/draft-a-license) that names the request, or [decline it](/api-reference/license-requests/decline-a-license-request).
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseRequestEvent" }
            examples:
              request_created:
                summary: Ridgeline asks Maya Okafor to add TV
                value:
                  id: evt_ape2agq9ysjxqx0ffvs2hsd6jb
                  object: event
                  type: license_request.created
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-10-17T18:10:01Z"
                  data:
                    object:
                      id: lrq_py3xqfvbjjcdhvf33y6c2w26jm
                      object: license_request
                      livemode: true
                      kind: change
                      status: sent
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      license_revision: null
                      check: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
                      requested_scope:
                        channels:
                          - social
                          - web
                          - tv
                        final_deliverables: 30
                      offer:
                        type: flat
                        flat:
                          amount: 1000000
                          currency: usd
                        schedule: on_acceptance
                      note: We would like to run the trail campaign images in a TV spot in the US and Canada, with six more final outputs.
                      decision_note: null
                      signed_at: null
                      declined_at: null
                      withdrawn_at: null
                      metadata:
                        campaign: trail-winter-tv
                      created_at: "2026-10-17T18:10:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license_draft.signed:
    post:
      operationId: webhookLicenseDraftSigned
      summary: license_draft.signed
      description: |
        Your draft was signed. `license` and `license_revision` name what was signed, and `signed_as_drafted` is `false` when the signer changed terms before signing. The licensee receives `license.issued` for a new license or `license.revision_pending` for a new revision, and `license.accepted` or `license.revised` follows when it accepts.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseDraftEvent" }
            examples:
              signed_as_drafted:
                summary: A new license signed as drafted
                value:
                  id: evt_pr5vw131yftgck1dn8rrx8xevm
                  object: event
                  type: license_draft.signed
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 3
                  created_at: "2026-09-27T11:15:01Z"
                  data:
                    object:
                      id: ldr_tw5hx5mq8q0j5wry9hp32ftj0p
                      object: license_draft
                      livemode: true
                      status: signed
                      kind: issue
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      license_request: null
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      signer: talent
                      signing_url: null
                      signed_as_drafted: true
                      license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      decision_note: null
                      note: Social and Ridgeline's own website only. TV needs a separate license.
                      created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                      expires_at: "2026-10-24T16:10:00Z"
                      signed_at: "2026-09-27T11:15:00Z"
                      declined_at: null
                      metadata:
                        deal_id: RDG-FW26-014
                      created_at: "2026-09-24T16:10:00Z"
                    previous_attributes:
                      status: open
                      license: null
                      signing_url: https://app.reflections.ai/sign/ldr_tw5hx5mq8q0j5wry9hp32ftj0p
                      signed_as_drafted: null
                      license_revision: null
                      signed_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  license_draft.declined:
    post:
      operationId: webhookLicenseDraftDeclined
      summary: license_draft.declined
      description: |
        The signer declined your draft. `decision_note` holds their note, if they wrote one. Nothing was signed.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/LicenseDraftEvent" }
            examples:
              declined_with_note:
                summary: The talent declined, with a note
                value:
                  id: evt_4d2rdzq6z0dr5v9yfe7x7vv384
                  object: event
                  type: license_draft.declined
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-09-23T10:40:01Z"
                  data:
                    object:
                      id: ldr_dj05ema2gyfqqr7b22qj9ncm94
                      object: license_draft
                      livemode: true
                      status: declined
                      kind: issue
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      license: null
                      license_request: null
                      scope:
                        facets:
                          - fct_5zba2q8v1m3n7p4r6s9t0wxyhk
                        modalities:
                          - image
                        kinds:
                          - depiction
                        purposes:
                          - advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                        window:
                          starts_at: "2026-10-01T00:00:00-04:00"
                          ends_at: "2027-03-31T00:00:00-04:00"
                          time_zone: America/New_York
                        adjustments:
                          reframe: true
                          background_extension: true
                          lighting: true
                          text_overlay: true
                          body_and_age: false
                          expression: false
                          hair: false
                          pose: false
                          wardrobe: true
                          objects: true
                          skin_retouch: false
                          endorsement: false
                        prohibited_changes:
                          - body_and_age
                          - expression
                          - hair
                          - pose
                          - skin_retouch
                          - endorsement
                        required_attributes:
                          - identity.samePerson
                          - appearance.bodyAndAge
                          - appearance.expression
                          - appearance.hair
                          - appearance.pose
                          - appearance.skinRetouch
                          - context.endorsement
                        rules:
                          never:
                            - Do not show alcohol or tobacco.
                          always: []
                          brief: null
                        release_policy: per_output_review
                        escalation_window: P7D
                        final_deliverables: 24
                        sessions:
                          permitted: false
                        material_access: []
                        platforms:
                          mode: any_connected
                          accounts: []
                        sublicense: none
                        training: prohibited
                        disclosure: brand
                        attribution: null
                        post_revocation:
                          policy: retain
                        exclusivity:
                          exclusive: false
                          category: null
                        conflicts: []
                        compensation:
                          type: per_unit
                          per_unit:
                            units: placements
                            rate:
                              amount: 25000
                              currency: usd
                            per: 1
                          minimum:
                            amount: 500000
                            currency: usd
                          schedule: monthly
                      terms_digest: sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431
                      signer: talent
                      signing_url: null
                      signed_as_drafted: null
                      license_revision: null
                      decision_note: Send me Ridgeline's shot list first. I want to see the scenes before I sign.
                      note: Social and web in the US and Canada, October to March.
                      created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                      expires_at: "2026-10-22T14:45:00Z"
                      signed_at: null
                      declined_at: "2026-09-23T10:40:00Z"
                      metadata:
                        deal_id: RDG-FW26-014
                      created_at: "2026-09-22T14:45:00Z"
                    previous_attributes:
                      status: open
                      signing_url: https://app.reflections.ai/sign/ldr_dj05ema2gyfqqr7b22qj9ncm94
                      decision_note: null
                      declined_at: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  escalation.created:
    post:
      operationId: webhookEscalationCreated
      summary: escalation.created
      description: |
        A check or a held output is waiting for a decision from the talent's side. Sent to representatives whose mandate has `review_outputs`. Decide before `expires_at` with [Resolve an escalation](/api-reference/escalations/resolve-an-escalation); an unanswered escalation becomes `deny`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/EscalationEvent" }
            examples:
              held_output:
                summary: A held output waiting for release
                value:
                  id: evt_421kgxwxhz1yrwcmaf101bjmbx
                  object: event
                  type: escalation.created
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-10-17T18:00:13Z"
                  data:
                    object:
                      id: esc_hk5zba2q8v1m3n7p4r6s9t0wxy
                      object: escalation
                      livemode: true
                      reason: release_review
                      reviewer: talent
                      status: open
                      expires_at: "2026-10-24T18:00:12Z"
                      resolved_at: null
                      note: null
                      subject:
                        object: generation
                        id: gen_6s9t0wxyhk5zba2q8v1m3n7p4r
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
                      license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
                      licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
                      licensee_name: Ridgeline
                      platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      platform_name: Northlight
                      use:
                        modality: image
                        kind: depiction
                        purpose: advertising
                        commercial: true
                        channels:
                          - social
                          - web
                        territories:
                          - US
                          - CA
                      inputs:
                        - role: prompt
                          text: Maya Okafor holding our new trail shoe on a rocky ridge at sunrise
                        - role: reference
                          sha256: 5e0b7c2d9f4a1e6b3c8d0f2a4e6b8c0d2f4a6e8b0c2d4f6a8e0b2c4d6f8a0b2c
                          media_type: image/jpeg
                          url: https://files.reflections.ai/esc_hk5zba2q8v1m3n7p4r6s9t0wxy/inputs/1?expires=1792260913&signature=wYC1cWiOWq9EYeAqdosHvg4fGmGo4aXnt9nCYu9FI74
                      reasons: []
                      findings:
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes
                          attribute: identity.samePerson
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments
                          attribute: appearance.wardrobe
                          result: preserved
                        - term: license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras
                          rule: Do not show alcohol or tobacco.
                          result: preserved
                      artifact:
                        sha256: 9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a
                        media_type: image/png
                        url: https://files.reflections.ai/esc_hk5zba2q8v1m3n7p4r6s9t0wxy/artifact?expires=1792260913&signature=YiOzSb3FffjcsVtdwSRH8r4FNWla9ElDVCdFoj5UN_s
                      request_digest: sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a
                      review_url: https://app.reflections.ai/review/esc_hk5zba2q8v1m3n7p4r6s9t0wxy
                      decision: null
                      decided_by: null
                      created_at: "2026-10-17T18:00:12Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  mandate.created:
    post:
      operationId: webhookMandateCreated
      summary: mandate.created
      description: |
        A talent appointed your account as a representative. `powers` lists what you may do for them.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/MandateEvent" }
            examples:
              manager_appointed:
                summary: A talent appointed a manager
                value:
                  id: evt_td2daf8rebqk19qb6bbfss9j0w
                  object: event
                  type: mandate.created
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 1
                  created_at: "2026-10-05T15:20:01Z"
                  data:
                    object:
                      id: mnd_ww2cs3e4j5tgqqxs7mt7746q4p
                      object: mandate
                      livemode: true
                      talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                      talent_name: Jonah Reyes
                      representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                      role: manager
                      powers:
                        - issue_licenses
                        - review_outputs
                        - receive_statements
                      status: active
                      starts_at: "2026-10-05T15:20:00Z"
                      ends_at: null
                      ended_at: null
                      revocation: null
                      created_at: "2026-10-05T15:20:00Z"
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  mandate.ended:
    post:
      operationId: webhookMandateEnded
      summary: mandate.ended
      description: |
        Your mandate ended: the talent ended it, or it reached `ends_at`. Talent-side calls for that talent fail with `mandate_required` from this moment, and open drafts are discarded. Licenses stay in force unless the talent revoked them with the mandate; the revocation in `revocation` lists those in `targets.licenses`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/MandateEvent" }
            examples:
              ended_by_talent:
                summary: The talent ended the mandate
                value:
                  id: evt_72z7c0jm4ezmm1xzvtmp4j6tm4
                  object: event
                  type: mandate.ended
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-29T13:02:11Z"
                  data:
                    object:
                      id: mnd_ww2cs3e4j5tgqqxs7mt7746q4p
                      object: mandate
                      livemode: true
                      talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
                      talent_name: Jonah Reyes
                      representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
                      role: manager
                      powers:
                        - issue_licenses
                        - review_outputs
                        - receive_statements
                      status: ended
                      starts_at: "2026-10-05T15:20:00Z"
                      ends_at: null
                      ended_at: "2026-10-29T13:02:10Z"
                      revocation: rvk_ch7rn89symf3em1rsp31ztxg9b
                      created_at: "2026-10-05T15:20:00Z"
                    previous_attributes:
                      status: active
                      ended_at: null
                      revocation: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

  statement.disputed:
    post:
      operationId: webhookStatementDisputed
      summary: statement.disputed
      description: |
        The talent's side disputed a statement. `dispute.reason` says why. When your usage records or payments change, the statement is reissued with `statement.issued`.
      parameters:
        - $ref: "#/components/parameters/WebhookId"
        - $ref: "#/components/parameters/WebhookTimestamp"
        - $ref: "#/components/parameters/WebhookSignature"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/StatementEvent" }
            examples:
              disputed:
                summary: Disputed by the talent's manager
                value:
                  id: evt_w761tpmf4w7qa0t9vzqs6pj3a8
                  object: event
                  type: statement.disputed
                  api_version: "2026-10-15"
                  livemode: true
                  account: null
                  sequence: 2
                  created_at: "2026-10-05T14:22:11Z"
                  data:
                    object:
                      id: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                      object: statement
                      livemode: true
                      license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
                      talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
                      licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
                      status: disputed
                      period:
                        start: "2026-09-01T00:00:00Z"
                        end: "2026-10-01T00:00:00Z"
                      currency: usd
                      lines:
                        - description: Speech in Maya Okafor's voice
                          units: seconds
                          reported: 41200
                          observed: 41236
                          billable: 41236
                          rate:
                            amount: 2
                            currency: usd
                          amount: 82472
                      amount_due: 82472
                      amount_paid: 0
                      reconciliation:
                        result: under_reported
                        detail: 36 seconds observed in generations with no usage record.
                      payments: []
                      due_at: "2026-10-31T00:00:00Z"
                      issued_at: "2026-10-02T08:00:00Z"
                      document_url: https://app.reflections.ai/statements/stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
                      created_at: "2026-09-01T00:00:00Z"
                      dispute:
                        reason: 36 seconds of September speech have no usage record. Report them so the statement reconciles.
                        disputed_at: "2026-10-05T14:22:10Z"
                    previous_attributes:
                      status: issued
                      dispute: null
      responses:
        "200":
          description: Return any 2xx status within 10 seconds. Anything else is retried.

components:
  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.
    ClientCredentials:
      type: http
      scheme: basic
      description: |
        A confidential OAuth client's `client_id` and `client_secret`, sent as HTTP Basic
        credentials. Register the client with your secret key to receive them; see
        [`POST /oauth/register`](/api-reference/oauth/register-a-client).

  parameters:
    ReflectionsVersion:
      name: Reflections-Version
      in: header
      required: false
      description: The dated API version. Defaults to the version your account is pinned to.
      schema: { type: string, example: "2026-10-15" }
    ReflectionsAccount:
      name: Reflections-Account
      in: header
      required: false
      description: |
        Act for a connected licensee. The value is the licensee's account ID. Requires an active
        connection between that account and yours.
      schema: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$" }
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: |
        A unique key for this operation, up to 255 characters. In test mode, POST keys are scoped
        to your account and mode and bind the endpoint and body for 24 hours. A different endpoint
        or body with the same key is refused.

        Initial live check and generation creation require a nonempty key. Each operation has a
        separate account-scoped namespace; retain the same API key, body and idempotency key for
        retries within 24 hours of creation. Pending checks return `409 idempotency_key_in_use`.
        Completed checks replay their sealed response; successful generation POSTs replay the
        original accepted `202`, so use GET for current state. Live verification is a read-only
        query that returns a fresh verification ID on each call, without exact response caching.

        The broader delegated-account contract also scopes keys to `Reflections-Account`;
        delegated requests and the other planned live POST operations remain unsupported.
      schema: { type: string, maxLength: 255 }
    Limit:
      name: limit
      in: query
      description: Number of objects to return, 1 to 100.
      schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
    Cursor:
      name: cursor
      in: query
      description: The `next_cursor` from the previous page.
      schema: { type: string }
    TalentId:
      name: talent_id
      in: path
      required: true
      description: The talent's ID, `tal_…`.
      example: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
      schema: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
    FacetId:
      name: facet_id
      in: path
      required: true
      description: The facet's ID, `fct_…`.
      example: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
      schema: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$" }
    LicenseId:
      name: license_id
      in: path
      required: true
      description: The license's ID.
      example: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
      schema: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
    LicenseRequestId:
      name: request_id
      in: path
      required: true
      description: The license request's ID.
      example: lrq_py3xqfvbjjcdhvf33y6c2w26jm
      schema: { type: string, pattern: "^lrq_[0-9a-hjkmnp-tv-z]{26}$" }
    ConnectionId:
      name: connection_id
      in: path
      required: true
      description: The connection's ID.
      example: con_av0baahbfheftkzxqbkns02qwf
      schema: { type: string, pattern: "^con_[0-9a-hjkmnp-tv-z]{26}$" }
    CheckId:
      name: check_id
      in: path
      required: true
      description: The check's ID.
      example: chk_3pg20xkepkscyp0qbpc4yq7ad2
      schema: { type: string, pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$" }
    GenerationId:
      name: generation_id
      in: path
      required: true
      description: The generation's ID.
      example: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
      schema: { type: string, pattern: "^gen_[0-9a-hjkmnp-tv-z]{26}$" }
    SessionId:
      name: session_id
      in: path
      required: true
      description: The session's ID.
      example: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
      schema: { type: string, pattern: "^ses_[0-9a-hjkmnp-tv-z]{26}$" }
    RevocationId:
      name: revocation_id
      in: path
      required: true
      description: The revocation's ID.
      example: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
      schema: { type: string, pattern: "^rvk_[0-9a-hjkmnp-tv-z]{26}$" }
    StatementId:
      name: statement_id
      in: path
      required: true
      description: The statement's ID.
      example: stmt_5p7r9t1v3x5z7b9d1f3h5k7m9q
      schema: { type: string, pattern: "^stmt_[0-9a-hjkmnp-tv-z]{26}$" }
    MandateId:
      name: mandate_id
      in: path
      required: true
      description: The mandate's ID.
      example: mnd_7nb1ef0wykcj3mkwaba3x20ez6
      schema: { type: string, pattern: "^mnd_[0-9a-hjkmnp-tv-z]{26}$" }
    EscalationId:
      name: escalation_id
      in: path
      required: true
      description: The escalation's ID.
      example: esc_t0wxyhk5zba2q8v1m3n7p4r6s9
      schema: { type: string, pattern: "^esc_[0-9a-hjkmnp-tv-z]{26}$" }
    LicenseDraftId:
      name: draft_id
      in: path
      required: true
      description: The draft's ID.
      example: ldr_hz4ngq81vhagynxm3ds9q2acz4
      schema: { type: string, pattern: "^ldr_[0-9a-hjkmnp-tv-z]{26}$" }
    PaymentId:
      name: payment_id
      in: path
      required: true
      description: The payment's ID, from the statement's `payments`.
      example: pay_sa9z70h0p3p3npjcjv3gfn3330
      schema: { type: string, pattern: "^pay_[0-9a-hjkmnp-tv-z]{26}$" }
    WebhookEndpointId:
      name: endpoint_id
      in: path
      required: true
      description: The endpoint's ID.
      example: we_5x7z9b1d3f5h7k9m1p3r5t7v9x
      schema: { type: string, pattern: "^we_[0-9a-hjkmnp-tv-z]{26}$" }
    EventId:
      name: event_id
      in: path
      required: true
      description: The event's ID, equal to the `webhook-id` header of its deliveries.
      example: evt_1h3k5m7p9r1t3v5x7z9b1d3f5h
      schema: { type: string, pattern: "^evt_[0-9a-hjkmnp-tv-z]{26}$" }
    WebhookId:
      name: webhook-id
      in: header
      required: true
      description: The event ID. Use it to ignore duplicate deliveries.
      schema: { type: string }
    WebhookTimestamp:
      name: webhook-timestamp
      in: header
      required: true
      description: Unix seconds when this delivery was signed. Reject deliveries more than 5 minutes old.
      schema: { type: string }
    WebhookSignature:
      name: webhook-signature
      in: header
      required: true
      description: |
        Space-separated `v1,<base64>` signatures: HMAC-SHA256 with your endpoint secret over
        `<webhook-id>.<webhook-timestamp>.<body>`. More than one appears while a secret rotates.
      schema: { type: string }

  headers:
    RequestId:
      description: Identifies this request. Include it when you contact support.
      schema: { type: string, example: "req_8f2k4m6p8r0t2v4x6z8b0d2f4h" }
    RateLimit:
      description: Remaining quota and seconds until it resets, as IETF RateLimit header fields.
      schema: { type: string, example: "\"checks\";r=184;t=1" }
    RateLimitPolicy:
      description: The policy the RateLimit field reports against.
      schema: { type: string, example: "\"checks\";q=200;w=1" }
    RetryAfter:
      description: Seconds to wait before retrying.
      schema: { type: integer }

  responses:
    BadRequest:
      description: The request was malformed or a parameter was invalid.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
          example:
            type: https://docs.reflections.ai/errors/parameter_invalid
            title: A parameter is invalid
            status: 400
            code: parameter_invalid
            param: use.territories[1]
            detail: "\"UK\" is not an ISO 3166-1 alpha-2 code. Use \"GB\"."
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    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
    Forbidden:
      description: The key may not do this, the licensee is not connected, or live mode is not activated for this operation (`live_not_activated`).
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
          example:
            type: https://docs.reflections.ai/errors/account_not_connected
            title: The licensee has not connected your platform
            status: 403
            code: account_not_connected
            detail: acct_2q8v1m3n7p4r6s9t0wxyhk5zba has no active connection with your account.
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    MandateRequired:
      description: Your account holds no active mandate for this talent with the power this call needs.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
          example:
            type: https://docs.reflections.ai/errors/mandate_required
            title: No mandate with the needed power
            status: 403
            code: mandate_required
            detail: Your mandate for tal_9t0wxyhk5zba2q8v1m3n7p4r6s does not include review_outputs.
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    NotFound:
      description: No such object for this account.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
          example:
            type: https://docs.reflections.ai/errors/resource_not_found
            title: No such object
            status: 404
            code: resource_not_found
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    Conflict:
      description: The request conflicts with the object's state or with a request still running.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
          example:
            type: https://docs.reflections.ai/errors/idempotency_key_in_use
            title: A request with this key is still running
            status: 409
            code: idempotency_key_in_use
            detail: Retry with the same key after a short wait.
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    Unprocessable:
      description: The request is well formed but cannot be applied.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
          example:
            type: https://docs.reflections.ai/errors/idempotency_key_reused
            title: This key was used for a different request
            status: 422
            code: idempotency_key_reused
            request_id: req_8f2k4m6p8r0t2v4x6z8b0d2f4h
    PayloadTooLarge:
      description: The request exceeds its byte limit. Sandbox inline media is at most 7 MiB decoded and the generation JSON body at most 10 MiB. Multipart uploads are planned.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
    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" }
    Timeout:
      description: Verification did not finish in time. Retry, or verify by receipt instead of by file.
      headers:
        Request-Id: { $ref: "#/components/headers/RequestId" }
      content:
        application/problem+json:
          schema: { $ref: "#/components/schemas/Problem" }
  schemas:
    # ---------- Shared ----------
    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
    Metadata:
      type: object
      description: Up to 50 keys of your own, each up to 40 characters, values up to 500 characters. Never put personal data here.
      additionalProperties: { type: string, maxLength: 500 }
      maxProperties: 50
    Digest:
      type: string
      description: A SHA-256 digest, `sha256:` followed by 64 lowercase hex characters.
      pattern: "^sha256:[0-9a-f]{64}$"
    Sha256Hex:
      type: string
      description: A SHA-256 digest of bytes, as 64 lowercase hex characters.
      pattern: "^[0-9a-f]{64}$"
    Address:
      type: string
      description: |
        Where a reason or finding rests, written as an address: `license:<id>/terms.<key>` for a
        term, `talent:<id>` for a talent's standing boundary.
      example: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.channels"
    Duration:
      type: string
      description: An ISO 8601 duration, such as `PT60S` or `P30D`.
      example: P30D
    ListBase:
      type: object
      required: [object, has_more]
      properties:
        object: { type: string, const: list, description: Always `list`. }
        has_more: { type: boolean, description: "Whether another page exists." }
        next_cursor: { type: [string, "null"], description: "Pass as `cursor` to read the next page." }
    DeletedObject:
      type: object
      required: [id, object, deleted]
      properties:
        id: { type: string, description: The ID of the deleted object. }
        object: { type: string, description: "The deleted object's type, such as `webhook_endpoint`." }
        deleted: { type: boolean, const: true, description: Always `true`. }

    # ---------- Vocabulary ----------
    Decision:
      type: string
      description: |
        `allow`: proceed and meet the obligations. `deny`: do not proceed. `escalate`: wait; a
        person with authority will decide, and an unanswered escalation becomes `deny`.
      enum: [allow, deny, escalate]
    Modality:
      type: string
      description: What will be generated. `speech` is a voice speaking words; `audio` is any other sound.
      enum: [image, video, speech, audio, text]
    UseKind:
      type: string
      description: |
        How the talent appears. `depiction`: shown or heard. `impersonation`: speaks or writes as
        the talent. `endorsement`: implies the talent approves something. `reference`: talked
        about, without synthesis; needs no license.
      enum: [depiction, impersonation, endorsement, reference]
    Purpose:
      type: string
      enum: [advertising, branded_content, entertainment, editorial, personal, education, political]
    Channel:
      type: string
      description: Where the output will appear.
      enum: [social, web, in_app, streaming, tv, cinema, out_of_home, print, audio, email, retail, games, private]
    Territory:
      type: string
      description: An ISO 3166-1 alpha-2 country code, or `WW` for worldwide.
      pattern: "^([A-Z]{2})$"
      example: US
    Use:
      type: object
      required: [modality, kind, purpose, commercial]
      properties:
        modality: { $ref: "#/components/schemas/Modality", description: What will be generated. }
        kind: { $ref: "#/components/schemas/UseKind", description: How the talent appears in the output. }
        purpose: { $ref: "#/components/schemas/Purpose", description: What the output is for. }
        commercial:
          type: boolean
          description: Whether anyone earns money from the output, including through advertising.
        channels:
          type: array
          items: { $ref: "#/components/schemas/Channel" }
          maxItems: 20
          description: Required when `commercial` is true.
        territories:
          type: array
          items: { $ref: "#/components/schemas/Territory" }
          maxItems: 50
          description: Required when `commercial` is true.
    Execution:
      type: object
      description: |
        Which model will run, or ran, the request. Reflections records it as stated by the
        platform (`assurance: attested`).
      properties:
        provider: { type: string, maxLength: 100, description: "The model provider." }
        model: { type: string, maxLength: 100, description: The model's name at the provider. }
        candidates: { type: integer, minimum: 1, maximum: 16, description: "Outputs this request will produce." }
        job_id: { type: string, maxLength: 200, description: "The provider's ID for the job." }
    EndUser:
      type: object
      description: |
        The person your product acts for. Send a stable ID scoped to your platform, never an email
        or a name. Reflections stores only an HMAC of it.
      required: [id]
      properties:
        id:
          type: string
          maxLength: 200
          description: |
            Your stable ID for the person, up to 200 characters. Never an email or a name.
        type:
          type: string
          enum: [consumer, business]
          default: consumer
          description: |
            `consumer` for a person acting for themselves, `business` for one acting for a company.
    Input:
      type: object
      description: |
        One part of the request a model receives, in order. Send text inline; send media as a
        file ID, or as `sha256` with a `url` Reflections can fetch.
      required: [role]
      properties:
        role:
          type: string
          enum: [prompt, system, negative_prompt, rewritten_prompt, script, reference, voice_sample, mask, context]
          description: |
            `prompt`: the user's words. `system`: instructions you add. `rewritten_prompt`: your
            expansion of the prompt, if the model receives that instead. `script`: words to be
            spoken. `reference`, `voice_sample`, `mask`: media the model receives. `context`:
            conversation history the model receives.
        text:
          type: string
          maxLength: 32000
          description: The text, for every role except `reference`, `voice_sample` and `mask`.
        file:
          type: string
          pattern: "^file_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            A file ID from `POST /v1/files`, for a `reference`, `voice_sample` or `mask` input.
        url:
          type: string
          format: uri
          description: |
            A URL Reflections can fetch the media from. Send `sha256` and `media_type` with it.
        sha256:
          $ref: "#/components/schemas/Sha256Hex"
          description: |
            SHA-256 of the bytes, in hex: of the media at `url`, or of a text input's UTF-8 bytes
            when `prompt_handling.mode` is `withheld`.
        media_type:
          type: string
          example: image/png
          description: |
            The MIME type of the media at `url`, or `text/plain` for a withheld text input.
    PromptHandling:
      type: object
      properties:
        mode:
          type: string
          enum: [full, redacted, withheld]
          default: full
          description: |
            `full`: text is sent as is. `redacted`: you removed personal data first, and the
            digest covers the redacted text. `withheld`: no text is sent. Send each text input as
            `role`, `sha256` of its UTF-8 bytes and `media_type: text/plain`, and name the talent
            in `talent`, because names cannot be matched in text Reflections does not see. Rules
            that need the text are checked on the output instead.
        retention:
          type: string
          enum: [default, none]
          default: default
          description: "`none`: delete text as soon as the check is decided, even on `deny` or `escalate`."

    # ---------- Decisions ----------
    ReasonCode:
      type: string
      description: Why a use was denied or escalated, or a session terminated. See the reason code catalog.
      enum:
        - no_license
        - license_pending_acceptance
        - license_revoked
        - license_suspended
        - window_not_started
        - window_ended
        - terms_unreadable
        - account_not_licensee
        - material_unavailable
        - adjustment_not_licensed
        - facet_not_licensed
        - kind_not_licensed
        - modality_not_licensed
        - purpose_not_licensed
        - channel_not_licensed
        - territory_not_licensed
        - commercial_use_not_licensed
        - platform_not_licensed
        - delivery_limit_reached
        - monthly_limit_reached
        - talent_prohibits
        - prohibited_appearance_change
        - prohibited_endorsement
        - prohibited_custom_term
        - identity_not_preserved
        - prohibited_speech
        - prohibited_motion
        - narration_mismatch
        - voice_rule
        - unsupported_rule
        - attribute_unverifiable
        - output_unverifiable
        - ambiguous_talent
        - review_required
        - unverifiable_request
        - evaluation_unavailable
        - authority_changed
        - provenance_failed
        - hold_expired
        - review_declined
        - review_expired
        - session_not_permitted
        - renewal_missed
        - sample_missed
    Reason:
      type: object
      required: [code, stage, sentence]
      properties:
        code: { $ref: "#/components/schemas/ReasonCode", description: A stable reason code. Branch on it. }
        stage: { type: string, enum: [check, generation, session], description: "Where it was decided: `check`, `generation` or `session`." }
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent the reason concerns. }
        term:
          $ref: "#/components/schemas/Address"
          description: The license term or standing rule the reason rests on, as an address.
        sentence:
          type: string
          description: The reason in the license's own words. Show it to your user as written.
    ObligationType:
      type: string
      description: |
        `generation_check`: submit outputs before delivery. `hold_until_release`: deliver nothing
        until the reviewer releases it. `draft_watermark`: mark drafts shown while held.
        `generation_instructions`: pass the instructions to the model. `disclosure`,
        `attribution`: label the output as stated. `c2pa_manifest`: embed the `c2pa` assertion.
        `no_training`: never train on the material. `delete_material`: delete it within `within`.
        `usage_report`: report usage within `within`.
      enum:
        - generation_check
        - hold_until_release
        - draft_watermark
        - generation_instructions
        - disclosure
        - attribution
        - c2pa_manifest
        - no_training
        - delete_material
        - usage_report
    Obligation:
      type: object
      description: Something you must do to proceed. Each type uses only the fields listed for it.
      required: [type]
      properties:
        type:
          $ref: "#/components/schemas/ObligationType"
          description: |
            The kind of obligation. Treat a type you do not know as unmet: do not generate or
            deliver.
        required:
          type: string
          enum: [all, sampled]
          description: "`generation_check`: submit every output, or the sampled share in `sample_rate`."
        sample_rate:
          type: number
          minimum: 0
          maximum: 1
          description: |
            `generation_check` with `required: sampled`: the share of outputs to submit, from 0 to
            1, chosen at random.
        reviewer:
          type: string
          enum: [talent, representative, reflections]
          description: "`hold_until_release`: who releases each output."
        instructions:
          type: array
          items: { type: string }
          description: "`generation_instructions`: include these in what the model receives."
        level:
          type: string
          enum: [licensed, brand, scope]
          description: "`disclosure`: `licensed` says the person's likeness is licensed; `brand` adds who licensed it; `scope` adds the use."
        text: { type: string, description: "`disclosure` and `attribution`: the words to show." }
        placement:
          type: string
          enum: [visible, metadata, both]
          description: "`disclosure`: where the label goes."
        material:
          type: string
          enum: [references, voice, outputs]
          description: "`delete_material` and `no_training`: what the obligation covers."
        within:
          allOf: [{ $ref: "#/components/schemas/Duration" }]
          description: "The deadline. `delete_material`: counted from the decision. `usage_report`: from the generation's decision or the session's end."
        units:
          type: string
          enum: [outputs, seconds, characters, placements, impressions]
          description: "`usage_report`: the unit to report."
        term: { $ref: "#/components/schemas/Address", description: The address of the license term the obligation comes from. }
    Authorization:
      type: object
      description: |
        Proof that a check allowed a use. A generation tool or provider verifies `token` offline
        against the JWKS before it generates. For the initial live image submission, send the
        allowed `check` ID; the server reads its stored token. GenerationCreate has no separate
        authorization-token field.
      required: [token, max_generations, generations_used, expires_at]
      properties:
        token: { type: string, description: "A JWS with `typ` `tlp-auth+jwt`." }
        max_generations:
          type: integer
          minimum: 1
          description: |
            How many generations it covers. A generation past it fails with `409
            authorization_consumed`.
        generations_used: { type: integer, minimum: 0, description: How many generations have been submitted under it. }
        expires_at:
          type: string
          format: date-time
          description: |
            When it expires, at most 15 minutes after it was issued. A generation after it fails
            with `409 check_expired`.
    Escalation:
      type: object
      required: [id, reason, reviewer, status, expires_at]
      properties:
        id: { type: string, pattern: "^esc_[0-9a-hjkmnp-tv-z]{26}$", description: "The escalation's ID, `esc_` followed by 26 characters." }
        reason:
          type: string
          enum: [judgment, unverifiable, evaluation_unavailable, release_review]
          description: |
            `judgment`: a rule needs a person to read it. `unverifiable`: a protected attribute
            could not be confirmed. `evaluation_unavailable`: the check could not finish.
            `release_review`: every output under this license is released by a person.
        reviewer:
          type: string
          enum: [talent, representative, reflections]
          description: |
            `talent`: the talent, or a representative whose mandate has `review_outputs`.
            `representative`: only the talent's representatives. `reflections`: Reflections trust
            and safety, under a platform license.
        status:
          type: string
          enum: [open, allowed, denied, expired, cancelled]
          description: |
            `open` until it closes: `allowed` or `denied` by the reviewer, `expired` at
            `expires_at`, or `cancelled` when you cancel the check, withdraw the output, or another
            talent's escalation decides the check.
        expires_at:
          type: string
          format: date-time
          description: |
            When an unanswered escalation becomes `deny`: 7 days after it opens, or the license's
            shorter `escalation_window`.
        resolved_at:
          type: [string, "null"]
          format: date-time
          description: When the escalation was decided, expired or cancelled. Null while `open`.
        note: { type: [string, "null"], maxLength: 500, description: "The reviewer's note, if they wrote one." }
    Remedy:
      type: object
      description: What would change a `deny`.
      required: [type]
      properties:
        type:
          type: string
          enum: [license_request, license_change, disambiguate, retry_with_hold]
          description: |
            `license_request`: no license covers this; request one. `license_change`: a license
            exists but is narrower; request a change. `disambiguate`: name the talent explicitly.
            `retry_with_hold`: retry with `on_escalate: hold` to let a person review.
        license: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: "The license to change, for `license_change`." }
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent to send a license request to. }
        suggested_scope:
          $ref: "#/components/schemas/LicenseScopeRequest"
          description: |
            The scope that would allow the use, ready to send as `requested_scope` on a license
            request.
    CheckTalent:
      type: object
      required: [talent, name, matched_by, confidence, decision]
      properties:
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent's ID. }
        name: { type: string, description: "The talent's name, to show your user." }
        matched_by:
          type: string
          enum: [explicit, name, alias, indirect, reference_image, voice_sample]
          description: |
            How the request invokes the talent: `explicit` from `talent`, `name` or `alias` in text,
            `indirect` for a reference such as a role, or `reference_image` or `voice_sample` from
            media.
        confidence:
          type: string
          enum: [exact, high, medium, low]
          description: |
            How certain the match is. Every talent at `medium` or higher is treated as invoked.
        decision:
          $ref: "#/components/schemas/Decision"
          description: |
            This talent's decision. The check's `decision` is the most restrictive across `talent`.
        facets:
          type: array
          items: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$" }
          description: The talent's facets the use covers.
        license:
          type: [string, "null"]
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: The license that decided this talent's use. Null when no license applies.
        license_revision:
          type: [string, "null"]
          pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$"
          description: The revision of `license` that applied. Null when no license applies.
        terms_digest:
          description: The `terms_digest` of that revision. Null when no license applies.
          oneOf:
            - $ref: "#/components/schemas/Digest"
            - type: "null"
        escalation:
          type: [string, "null"]
          pattern: "^esc_[0-9a-hjkmnp-tv-z]{26}$"
          description: This talent's escalation, when their side must decide. Each escalated talent has their own.
    CheckStatus:
      type: string
      description: |
        `allowed`, `denied`: decided. `escalated`: waiting for a person; it ends `allowed`, or
        `denied` with `review_declined` or, after `escalation.expires_at`, `hold_expired`.
        `consumed`: every allowed generation was used. `expired`: an allowed check's authorization
        expired unused. `cancelled`: you cancelled it.
      enum: [allowed, denied, escalated, consumed, expired, cancelled]
    CheckCreate:
      type: object
      required: [inputs, use]
      properties:
        talent:
          type: array
          description: Talent your user picked. The inputs are still resolved for anyone else.
          items: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
          maxItems: 10
        exclude_talent:
          type: array
          description: Talent your user confirmed they did not mean.
          items: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        facet: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$", description: "A specific facet, such as one of several voices." }
        license: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: Use this license. By default the narrowest license that allows the use is chosen. }
        inputs:
          type: array
          minItems: 1
          maxItems: 64
          items: { $ref: "#/components/schemas/Input" }
          description: |
            Everything the model will receive, in order: the user's prompt, your system text, any
            rewritten prompt, references and conversation history.
        use:
          $ref: "#/components/schemas/Use"
          description: How the output will be used. A different use needs a new check.
        end_user:
          $ref: "#/components/schemas/EndUser"
          description: The person the request is for. Send it on every check made for a person.
        execution:
          $ref: "#/components/schemas/Execution"
          description: |
            The model that will run the request and how many outputs it will make. `provider` and
            `model` are part of `request_digest`.
        on_escalate:
          type: string
          enum: [hold, deny]
          default: hold
          description: "`deny`: never escalate; return `deny` with `review_required` instead. Use it for interactive products."
        reuse:
          type: object
          description: |
            Let one decision cover several generations of the same use, talent, execution and end
            user until `max_generations` or `ttl` runs out, even when later inputs differ. Each
            generation is still checked on its output. Generations under `reuse` omit
            `candidate_index`.
          properties:
            max_generations: { type: integer, minimum: 1, maximum: 1000, description: "Generations the window covers, up to 1,000." }
            ttl:
              allOf: [{ $ref: "#/components/schemas/Duration" }]
              description: How long the window lasts. At most `PT15M`.
        prompt_handling:
          $ref: "#/components/schemas/PromptHandling"
          description: |
            How text inputs reach Reflections: `full` by default, `redacted` or `withheld`.
        metadata: { $ref: "#/components/schemas/Metadata", description: "Your own keys, returned on the check." }
    Check:
      type: object
      required: [id, object, livemode, status, decision, talent, use, reasons, obligations, request_digest, created_at]
      properties:
        id: { type: string, pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$", description: "The check's ID, `chk_` followed by 26 characters." }
        object: { type: string, const: check, description: Always `check`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        status:
          $ref: "#/components/schemas/CheckStatus"
          description: |
            Where the check is now. An `allow` can later become `consumed`, `expired` or
            `cancelled`; an `escalate` ends `allowed`, `denied` or `cancelled`.
        decision:
          $ref: "#/components/schemas/Decision"
          description: |
            `allow`, `deny` or `escalate`. An escalated check's decision becomes `allow` or `deny`
            when a person decides or the escalation expires.
        talent:
          type: array
          items: { $ref: "#/components/schemas/CheckTalent" }
          description: |
            Each protected talent the request invokes, with that talent's own decision and license.
            Empty when none is found.
        use: { $ref: "#/components/schemas/Use", description: "The use the check decided, as you sent it." }
        reasons:
          type: array
          items: { $ref: "#/components/schemas/Reason" }
          description: Why the use was denied or escalated. Empty on `allow`.
        obligations:
          type: array
          items: { $ref: "#/components/schemas/Obligation" }
          description: What you must do to proceed. Empty unless `decision` is `allow`.
        authorization:
          description: |
            Proof of the `allow`. Pass `token` to the tool or provider that generates. Null unless
            `decision` is `allow`.
          oneOf:
            - $ref: "#/components/schemas/Authorization"
            - type: "null"
        escalation:
          description: |
            The escalation, when the check is `escalated` or was decided by a person. When several
            talent are escalated, each has their own, named in `talent[].escalation`. While the
            check is open, this field shows the open one that expires first, so its `expires_at` is
            when the check becomes `deny`. Once decided, it shows the one that decided: the first
            `deny` or expiry, or the last `allow`. The others still open are then `cancelled`.
          oneOf:
            - $ref: "#/components/schemas/Escalation"
            - type: "null"
        remedy:
          description: |
            What would change a `deny`. Null for other decisions, and when no change can help, as
            with `talent_prohibits`.
          oneOf:
            - $ref: "#/components/schemas/Remedy"
            - type: "null"
        request_digest:
          allOf: [{ $ref: "#/components/schemas/Digest" }]
          description: Digest of the inputs, use and execution this check decided. Without `reuse`, the authorization covers only this request; with `reuse`, it also covers later generations of the same use, talent, execution and end user.
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The account that holds the license: the licensee named in `Reflections-Account`, or your
            own account under a platform license.
        platform: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The account that ran the check. }
        session:
          type: [string, "null"]
          pattern: "^ses_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The session this check started, for a check run by `POST /v1/sessions`. Null otherwise.
        receipt:
          type: [string, "null"]
          pattern: "^rcpt_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The receipt that records the decision. Null until an escalated check is decided.
        metadata: { $ref: "#/components/schemas/Metadata", description: Your metadata from the request. }
        created_at: { type: string, format: date-time, description: When the check was created. }
    CheckList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Check" }
              description: The checks on this page, newest first.

    # ---------- Generations ----------
    Artifact:
      type: object
      description: The sandbox accepts inline data or SHA-256 attestation. Inline data is at most 7 MiB decoded; the entire JSON body is at most 10 MiB. File IDs and URLs are planned contract forms.
      required: [sha256]
      properties:
        file: { type: string, pattern: "^file_[0-9a-hjkmnp-tv-z]{26}$", description: A file uploaded with `purpose=output`. }
        url: { type: string, format: uri, description: A URL Reflections can fetch the bytes from. }
        data: { type: string, description: "Base64 bytes. Sandbox limit: 7 MiB decoded (7,340,032 bytes); total JSON request limit: 10 MiB.", contentEncoding: base64 }
        sha256:
          $ref: "#/components/schemas/Sha256Hex"
          description: |
            The SHA-256 of the bytes. If the bytes Reflections receives differ, the call fails with
            `422 artifact_digest_mismatch`.
        media_type: { type: string, example: image/png, description: "The bytes' media type, such as `image/png`." }
        duration_ms: { type: integer, minimum: 0, description: "For audio and video." }
    Fingerprint:
      type: object
      description: |
        A fingerprint of a file, for verification when you cannot send the file itself. It matches
        the file to a registered output; it supports no rule checks.
      properties:
        perceptual_hash:
          type: object
          description: A perceptual hash of the file.
          required: [algorithm, value]
          properties:
            algorithm:
              type: string
              enum: [pdq, vpdq, chromaprint]
              description: "`pdq` for images, `vpdq` for video, `chromaprint` for audio."
            value:
              type: string
              description: |
                The hash in the algorithm's standard text form, such as 64 hex characters for `pdq`.
        embeddings:
          type: array
          items:
            type: object
            required: [model, vector]
            properties:
              model:
                type: string
                enum: [reflections-face-1, reflections-voice-1]
                description: |
                  The model that computed `vector`: `reflections-face-1` for faces,
                  `reflections-voice-1` for voices.
              vector: { type: string, contentEncoding: base64, description: "Little-endian float32 values." }
          description: |
            Optional face or voice embeddings of the file, used with the hash to look it up.
    Finding:
      type: object
      required: [term, result]
      properties:
        term:
          $ref: "#/components/schemas/Address"
          description: The term's address, such as `license:lic_…/terms.neverExtras`.
        attribute: { type: string, description: "A protected attribute, such as `identity.samePerson`." }
        rule: { type: string, description: "A rule the talent wrote, as written." }
        result:
          type: string
          enum: [preserved, violated, unchecked]
          description: "`unchecked`: the check could not read this rule. Talent-written rules that are unchecked are delivered and recorded; protected attributes never are."
        detail: { type: string, description: "What the check saw, for a `violated` result." }
    GenerationStatus:
      type: string
      description: |
        `checking`: not decided yet. `allowed`: deliver. `denied`: never deliver. `held`: waiting
        for release. `released`: a reviewer released it; deliver. `expired`: never reviewed.
        `withdrawn`: you withdrew it.
      enum: [checking, allowed, denied, held, released, expired, withdrawn]
    GenerationCreate:
      type: object
      required: [artifact]
      oneOf:
        - required: [check]
        - required: [session]
      properties:
        check: { type: string, pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$", description: "The check this output was made under. Required unless `session` is set." }
        session: { type: string, pattern: "^ses_[0-9a-hjkmnp-tv-z]{26}$", description: "The session this output was made in, instead of a `check`." }
        candidate_index: { type: integer, minimum: 0, maximum: 15, description: "Which of the check's `execution.candidates` this is, from 0. Omit under `reuse`." }
        artifact:
          $ref: "#/components/schemas/Artifact"
          description: The output's bytes, as a file ID, a URL or base64 `data`, with their SHA-256.
        execution:
          $ref: "#/components/schemas/Execution"
          description: The run that made the output. Send `job_id` when the provider gives one.
        transcript: { type: string, maxLength: 32000, description: "Words spoken in the output, if you have them. Reflections transcribes regardless." }
        watermark:
          type: object
          description: A watermark you applied, so verification can join it to this generation.
          properties:
            algorithm: { type: string, description: The watermarking method you used. }
            id: { type: string, description: "The watermark's identifier, as embedded in the output." }
        metadata: { $ref: "#/components/schemas/Metadata", description: "Your own keys, returned on the generation." }
    C2paAssertion:
      type: object
      description: Add this assertion to the output's C2PA manifest, under `label`.
      required: [label, data]
      properties:
        label:
          type: string
          const: ai.reflections.license
          description: Always `ai.reflections.license`. Use it as the assertion's label.
        data:
          type: object
          description: "The assertion's data, copied unchanged: the receipt JWS and its public page."
          required: [receipt, verify_url]
          properties:
            receipt: { type: string, description: "The receipt JWS." }
            verify_url:
              type: string
              format: uri
              description: The receipt's public page, `https://app.reflections.ai/r/{receipt_id}`.
    Generation:
      type: object
      required: [id, object, livemode, status, assurance, created_at]
      properties:
        id: { type: string, pattern: "^gen_[0-9a-hjkmnp-tv-z]{26}$", description: "The generation's ID, `gen_` followed by 26 characters." }
        object: { type: string, const: generation, description: Always `generation`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        check:
          type: [string, "null"]
          pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$"
          description: The check the output was made under. Null for an output made in a session.
        session:
          type: [string, "null"]
          pattern: "^ses_[0-9a-hjkmnp-tv-z]{26}$"
          description: The session the output was made in. Null for an output made under a check.
        candidate_index:
          type: [integer, "null"]
          description: |
            Which of the check's candidates this is, from 0. Null under `reuse` and for an output
            made in a session.
        status:
          $ref: "#/components/schemas/GenerationStatus"
          description: Where the output is. Deliver only on `allowed` or `released`.
        decision:
          description: |
            `allow`, `deny`, or `escalate` while a reviewer must release the output. Null while
            `status` is `checking`.
          oneOf:
            - $ref: "#/components/schemas/Decision"
            - type: "null"
        artifact:
          type: [object, "null"]
          description: The output that was checked.
          properties:
            file:
              type: [string, "null"]
              description: |
                The file the output was uploaded as. Null when it was sent as `url` or `data`.
            sha256:
              $ref: "#/components/schemas/Sha256Hex"
              description: |
                The SHA-256 of the checked bytes. The receipt carries it as `artifact_sha256`.
            media_type: { type: string, description: "The output's media type, such as `image/png`." }
            duration_ms:
              type: [integer, "null"]
              description: Length in milliseconds, for audio and video. Null otherwise.
        execution: { $ref: "#/components/schemas/Execution", description: "The run that made the output, as you stated it." }
        findings:
          type: array
          items: { $ref: "#/components/schemas/Finding" }
          description: Each rule checked on the bytes, with its result.
        unchecked_terms:
          type: array
          items: { $ref: "#/components/schemas/Address" }
          description: |
            Addresses of rules the talent wrote that could not be checked on these bytes. They do
            not withhold the output.
        reasons:
          type: array
          items: { $ref: "#/components/schemas/Reason" }
          description: Why the output was denied or expired. Empty otherwise.
        obligations:
          type: array
          items: { $ref: "#/components/schemas/Obligation" }
          description: |
            What you must do with this output, such as embed `c2pa` and show the disclosure, or keep
            it private while `held`.
        escalation:
          description: The release review, when a person must release the output. Null otherwise.
          oneOf:
            - $ref: "#/components/schemas/Escalation"
            - type: "null"
        assurance:
          type: string
          enum: [observed, attested]
          description: "`observed`: Reflections checked these bytes. `attested`: Reflections recorded what you stated without checking it."
        receipt:
          type: [string, "null"]
          pattern: "^rcpt_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The receipt that records the decision. Null while the output is `checking` or `held`,
            and after a withdrawal from review.
        c2pa:
          description: |
            The assertion to embed in the output's C2PA manifest before you deliver it. Null unless
            `decision` is `allow`.
          oneOf:
            - $ref: "#/components/schemas/C2paAssertion"
            - type: "null"
        watermark:
          type: [object, "null"]
          description: The watermark you registered on the generation. Null if none.
          properties:
            algorithm: { type: string, description: The watermarking method you used. }
            id: { type: string, description: "The watermark's identifier, as embedded in the output." }
        metadata: { $ref: "#/components/schemas/Metadata", description: Your metadata from the request. }
        created_at: { type: string, format: date-time, description: When the output was submitted. }
        decided_at:
          type: [string, "null"]
          format: date-time
          description: When the output was allowed, released, denied or expired. Null otherwise.
    GenerationList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Generation" }
              description: The generations on this page, newest first.

    # ---------- Sessions ----------
    SessionCreate:
      type: object
      required: [inputs, use]
      properties:
        talent:
          type: array
          items: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
          maxItems: 4
          description: |
            Talent your user picked, up to 4. The inputs are still resolved for anyone else.
        facet: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$", description: "A specific facet, such as one of several voices." }
        license:
          type: string
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            Use this license. By default the narrowest license that allows the use is chosen.
        inputs:
          type: array
          minItems: 1
          items: { $ref: "#/components/schemas/Input" }
          description: |
            What the model receives when the session starts, such as your system text, in order.
        use: { $ref: "#/components/schemas/Use", description: How the session's output will be used. }
        end_user: { $ref: "#/components/schemas/EndUser", description: The person the session is for. }
        execution: { $ref: "#/components/schemas/Execution", description: The model that runs the session. }
        max_duration:
          $ref: "#/components/schemas/Duration"
          description: |
            The longest the session may run, such as `PT30M`. The stream sends a `max_duration`
            warning before it is reached.
        metadata: { $ref: "#/components/schemas/Metadata", description: "Your own keys, returned on the session." }
    Sampling:
      type: object
      properties:
        audio_window_max:
          $ref: "#/components/schemas/Duration"
          description: |
            Submit an `audio` sample for every window of generated speech, each no longer than this,
            such as `PT15S`.
        transcript:
          type: string
          enum: [every_turn, none]
          description: |
            `every_turn`: submit a `transcript` sample with the words of each turn. `none`: no
            transcript samples.
        frame_interval: { $ref: "#/components/schemas/Duration", description: "For video, submit one `frame` sample per interval." }
    Session:
      type: object
      required: [id, object, livemode, status, check, created_at]
      properties:
        id: { type: string, pattern: "^ses_[0-9a-hjkmnp-tv-z]{26}$", description: "The session's ID, `ses_` followed by 26 characters." }
        object: { type: string, const: session, description: Always `session`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        status:
          type: string
          enum: [active, denied, ended, terminated]
          description: |
            `active`: renew and submit samples. `denied`: the check did not allow it; `reasons` say
            why. `ended`: you ended it. `terminated`: Reflections ended it; `termination` says why.
        check:
          type: string
          pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$"
          description: The check Reflections ran on the session's inputs when it started.
        license: { type: [string, "null"], pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: The license the session runs under. Null when none applies. }
        talent:
          type: array
          items: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
          description: The talent the session covers.
        token: { type: [string, "null"], description: "A JWS with `typ` `tlp-session+jwt`. Null when the session is not active." }
        expires_at:
          type: [string, "null"]
          format: date-time
          description: |
            When the current token expires, 5 minutes after it was issued. Null when the session is
            not active.
        renew_every: { $ref: "#/components/schemas/Duration", description: "How often to renew the token: `PT60S`." }
        sampling: { $ref: "#/components/schemas/Sampling", description: "Which samples to submit, and how often." }
        obligations:
          type: array
          items: { $ref: "#/components/schemas/Obligation" }
          description: What you must do for the whole session, such as show the disclosure.
        reasons:
          type: array
          items: { $ref: "#/components/schemas/Reason" }
          description: Why the session was denied. Empty otherwise.
        stream_url:
          type: [string, "null"]
          format: uri
          description: |
            The session stream's WebSocket URL. Stay connected to receive `session.terminated`. Null
            when the session is denied.
        termination:
          type: [object, "null"]
          description: |
            Why and when Reflections ended the session. Null unless `status` is `terminated`. The
            session stream's `session.terminated` message carries the same fields.
          required: [reason, sentence, revocation, sample, at]
          properties:
            reason:
              $ref: "#/components/schemas/ReasonCode"
              description: A reason code, such as `license_revoked` or `prohibited_custom_term`.
            sentence:
              type: string
              description: The reason in the license's own words. Show it to your user as written.
            talent:
              type: string
              pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$"
              description: The talent it concerns, when the session has several.
            term:
              $ref: "#/components/schemas/Address"
              description: The license term or standing rule it rests on, as an address.
            revocation:
              type: [string, "null"]
              pattern: "^rvk_[0-9a-hjkmnp-tv-z]{26}$"
              description: The revocation that ended the session, for `license_revoked` and `license_suspended`.
            sample:
              type: [string, "null"]
              pattern: "^smp_[0-9a-hjkmnp-tv-z]{26}$"
              description: The sample that was denied, if one was.
            at:
              type: string
              format: date-time
              description: When Reflections ended the session. Report usage up to this time.
        ended_at:
          type: [string, "null"]
          format: date-time
          description: |
            When you ended the session with `POST /v1/sessions/{session_id}/end`. Null until then.
        metadata: { $ref: "#/components/schemas/Metadata", description: Your metadata from the request. }
        created_at: { type: string, format: date-time, description: When the session started. }
    SessionRenewal:
      type: object
      required: [token, expires_at]
      properties:
        token:
          type: string
          description: |
            The new session token, a JWS with `typ` `tlp-session+jwt`. Pass it to your voice
            provider if it verifies session tokens.
        expires_at:
          type: string
          format: date-time
          description: |
            When the new token expires, 5 minutes after it was issued. Never continue output past
            it.
    SampleCreate:
      type: object
      required: [kind]
      properties:
        kind:
          type: string
          enum: [audio, transcript, frame]
          description: |
            `audio`: a window of generated speech. `transcript`: the words of one turn. `frame`: one
            video frame.
        window:
          type: object
          description: Where the sample falls in the session, in milliseconds from its start.
          properties:
            start_ms: { type: integer, minimum: 0, description: Where the sample starts. }
            end_ms: { type: integer, minimum: 0, description: Where the sample ends. }
        data: { type: string, contentEncoding: base64, description: "Audio (`audio/wav`, `audio/ogg`) or a frame (`image/jpeg`), up to 2 MB." }
        media_type:
          type: string
          description: "`audio/wav` or `audio/ogg` for `audio`, `image/jpeg` for `frame`."
        text: { type: string, maxLength: 8000, description: "For `transcript`: the words of one turn." }
    Sample:
      type: object
      required: [id, object, session, kind, decision, created_at]
      properties:
        id: { type: string, pattern: "^smp_[0-9a-hjkmnp-tv-z]{26}$", description: "The sample's ID, `smp_` followed by 26 characters." }
        object: { type: string, const: session_sample, description: Always `session_sample`. }
        session: { type: string, pattern: "^ses_[0-9a-hjkmnp-tv-z]{26}$", description: The session the sample belongs to. }
        kind: { type: string, enum: [audio, transcript, frame], description: "`audio`, `transcript` or `frame`, as submitted." }
        decision:
          type: string
          enum: [allow, deny]
          description: |
            `deny` means stop output within one second and end the session; Reflections also
            terminates it.
        reasons:
          type: array
          items: { $ref: "#/components/schemas/Reason" }
          description: Why the sample was denied. Empty on `allow`.
        findings:
          type: array
          items: { $ref: "#/components/schemas/Finding" }
          description: Rules checked on the sample, with their results.
        created_at: { type: string, format: date-time, description: When Reflections received the sample. }

    # ---------- Account ----------
    Account:
      type: object
      required: [id, object, livemode, name, types, capabilities, status, api_version, created_at]
      properties:
        id:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            Unique identifier, prefixed `acct_`. A platform sends a licensee's ID in
            `Reflections-Account`.
        object: { type: string, const: account, description: Always `account`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        name: { type: string, description: "The name talent see on requests, licenses and receipts." }
        types:
          type: array
          description: How the account describes itself. Shown to talent. It grants nothing.
          items: { type: string, enum: [brand, agency, platform, studio, representative] }
        capabilities:
          type: array
          description: What the account may do. A capability is granted when Reflections approves the account for it.
          items:
            type: string
            enum: [hold_licenses, request_licenses, run_checks, act_for_licensees, represent_talent]
        status:
          type: string
          enum: [active, suspended]
          description: "`active`, or `suspended` while Reflections has suspended the account."
        api_version: { type: string, description: "The version requests use when they send no `Reflections-Version`." }
        platform:
          type: [object, "null"]
          description: Present when the account runs checks for connected licensees.
          properties:
            display_name: { type: string, description: "Shown to licensees on the connection screen." }
            url: { type: string, format: uri, description: The platform's website. }
            client_id: { type: string, pattern: "^cl_[0-9a-hjkmnp-tv-z]{26}$", description: "The OAuth client ID that sends licensees to the [authorization page](/api-reference/oauth/authorize-a-client) for a connection." }
        created_at: { type: string, format: date-time, description: When the account was created. }

    # ---------- Talent ----------
    Declaration:
      type: string
      description: |
        A talent's public answer for a kind of use. `allowed`: no license needed; follow the
        obligations. `license_required`: request a license. `prohibited`: never, and no license
        can be requested.
      enum: [allowed, license_required, prohibited]
    PostureRule:
      type: object
      description: One public declaration. Omitted fields match every value.
      required: [declaration]
      properties:
        modality: { $ref: "#/components/schemas/Modality", description: The modality the rule matches. }
        kind: { $ref: "#/components/schemas/UseKind", description: The use kind the rule matches. }
        purpose: { $ref: "#/components/schemas/Purpose", description: The purpose the rule matches. }
        commercial: { type: boolean, description: Whether the rule matches commercial or non-commercial uses. }
        declaration: { $ref: "#/components/schemas/Declaration", description: The talent's answer for the uses the rule matches. }
        obligations:
          type: array
          description: What a use declared `allowed` must do.
          items: { $ref: "#/components/schemas/Obligation" }
    Posture:
      type: object
      description: |
        The talent's standing, public answers, before any license. The most specific rule wins;
        `prohibited` wins a tie. A license can widen `license_required`, never `prohibited`.
      required: [default, rules, accepts_requests]
      properties:
        default: { $ref: "#/components/schemas/Declaration", description: The declaration that applies when no rule matches. }
        rules:
          type: array
          items: { $ref: "#/components/schemas/PostureRule" }
          description: |
            Declarations for particular uses. The most specific matching rule wins, and `prohibited`
            wins a tie.
        accepts_requests: { type: boolean, description: "Whether the talent accepts license requests through the API." }
    FacetSummary:
      type: object
      required: [id, type, label, status]
      properties:
        id: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier of the facet, prefixed `fct_`." }
        type: { $ref: "#/components/schemas/FacetType", description: The part of the talent's identity the facet covers. }
        label: { type: string, description: "The talent's name for the facet, such as \"Speaking voice\"." }
        status: { $ref: "#/components/schemas/FacetStatus", description: Whether the facet can be licensed. }
    Representation:
      type: object
      description: An account with a mandate to act for the talent.
      required: [account, name, role, powers]
      properties:
        account: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The representative's account ID. }
        name: { type: string, description: The representative's name. }
        role: { type: string, enum: [agency, manager, estate, union, legal], description: What the representative is to the talent. }
        powers:
          type: array
          items: { type: string, enum: [issue_licenses, review_outputs, revoke, receive_statements] }
          description: |
            What the mandate allows. `issue_licenses`: answer requests, and draft and sign licenses.
            `review_outputs`: decide escalations and release held outputs. `revoke`: revoke or
            suspend licenses. `receive_statements`: read, confirm and dispute statements.
    Talent:
      type: object
      required: [id, object, livemode, name, aliases, status, verification, protection, posture, facets, created_at]
      properties:
        id: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier, prefixed `tal_`." }
        object: { type: string, const: talent, description: Always `talent`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        name: { type: string, description: The name the talent confirmed. }
        aliases:
          type: array
          description: Other names the talent confirmed, such as a stage name or a transliteration.
          items: { type: string }
        status:
          type: string
          enum: [active, withdrawn]
          description: "`withdrawn`: the talent withdrew consent everywhere. Every check denies with `license_revoked` or `talent_prohibits`."
        verification:
          type: object
          description: |
            Proves a real adult controls this talent's account and signed their licenses. It does
            not prove who owns every right in the name.
          required: [verified]
          properties:
            verified:
              type: boolean
              description: |
                Whether Reflections verified that a real adult controls this talent's account.
            method:
              type: [string, "null"]
              enum: [id_document, representative, null]
              description: |
                How the talent was verified: with an identity document, or through a representative.
                `null` when not verified.
            verified_at: { type: [string, "null"], format: date-time, description: When the talent was verified. `null` when not verified. }
        protection:
          type: object
          description: How references are matched to this talent.
          required: [references]
          properties:
            references: { type: boolean, description: "Reference images and voice samples sent with a check are matched against this talent's face and voice." }
            modalities:
              type: array
              items: { $ref: "#/components/schemas/Modality" }
              description: The modalities in which reference media is matched against this talent.
        posture:
          $ref: "#/components/schemas/Posture"
          description: The talent's standing public answers for uses with no license.
        representation:
          type: array
          items: { $ref: "#/components/schemas/Representation" }
          description: |
            Accounts with a mandate to act for the talent, with each one's `role` and `powers`.
        facets:
          type: array
          items: { $ref: "#/components/schemas/FacetSummary" }
          description: |
            Each facet's `id`, `type`, `label` and `status`. Retrieve a facet for the rest.
        hcs_subject_id:
          type: [string, "null"]
          description: The talent's subject ID in the Human Consent Registry, when registered there.
        profile_url: { type: string, format: uri, description: "The talent's public page." }
        created_at: { type: string, format: date-time, description: When the talent's record was created. }
        updated_at: { type: string, format: date-time, description: When the talent last changed. }
    TalentList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Talent" }
              description: The talent on this page, newest first.
    TalentIndex:
      type: object
      description: |
        Every protected talent's names for matching on your side. `signature` is a detached JWS
        over the canonical `entries`; verify it against the JWKS before you use the index.
      required: [object, version, generated_at, expires_at, entries, signature]
      properties:
        object: { type: string, const: talent_index, description: Always `talent_index`. }
        version:
          type: string
          description: |
            Identifies this index. The `ETag` header carries the same value; send it in
            `If-None-Match`.
        generated_at: { type: string, format: date-time, description: When this index was built. }
        expires_at: { type: string, format: date-time, description: "Do not match against an index past this time." }
        normalization:
          type: string
          const: nfkc_casefold
          description: Normalize prompt text the same way before matching.
        entries:
          type: array
          items:
            type: object
            required: [talent, names]
            properties:
              talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent the names belong to. }
              names:
                type: array
                description: The name, aliases and transliterations, normalized.
                items: { type: string }
              common: { type: boolean, description: "The name is common enough that a match alone is weak evidence." }
          description: One entry for each protected talent.
        signature:
          type: string
          description: |
            A detached JWS, `ES256`, over the `tlp-json-1` canonical form of `entries`. Verify it
            against the JWKS before you use the index.

    # ---------- Facets ----------
    FacetType:
      type: string
      description: |
        `name`: the name in text. `likeness`: face and body in images and video. `voice`: the
        voice in speech. `twin`: a persona that speaks or writes as the talent. `knowledge`: a
        Volume of the talent's own words a model may draw on.
      enum: [name, likeness, voice, twin, knowledge]
    FacetStatus:
      type: string
      description: "`preparing`: not usable yet. `ready`: licensable. `withdrawn`: the talent withdrew it; licenses that cover it deny."
      enum: [preparing, ready, withdrawn]
    ProviderBinding:
      type: object
      description: |
        Where a facet lives at a model provider, such as a voice's ID at a voice provider. Shown
        only to that provider and to licensees whose license grants material access.
      required: [provider, kind, external_id, status]
      properties:
        provider: { type: string, description: The model provider that holds the copy. }
        kind:
          type: string
          enum: [voice, adapter, persona]
          description: "What the provider holds: a `voice`, a model `adapter` or a `persona`."
        external_id:
          type: string
          description: |
            The copy's ID at the provider. Call the provider with it, and name it when you report
            the copy deleted.
        status:
          type: string
          enum: [active, deleted]
          description: "`deleted` once the copy is gone from the provider. Stop using a deleted copy."
    Facet:
      type: object
      required: [id, object, livemode, talent, type, label, status, modalities, created_at]
      properties:
        id:
          type: string
          pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            Unique identifier, prefixed `fct_`. Send it in a check's `facet` to pick one of several
            facets of a type.
        object: { type: string, const: facet, description: Always `facet`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent this facet belongs to. }
        type: { $ref: "#/components/schemas/FacetType", description: The part of the talent's identity the facet covers. }
        label: { type: string, description: "The talent's name for it, such as \"Speaking voice\"." }
        status:
          $ref: "#/components/schemas/FacetStatus"
          description: |
            Whether the facet can be licensed. A withdrawal also arrives as a revocation with
            `scope: "facet"`.
        modalities:
          type: array
          description: What this facet can be used to generate.
          items: { $ref: "#/components/schemas/Modality" }
        material:
          type: [object, "null"]
          description: Reference material behind the facet. Download it through the material endpoint.
          properties:
            items: { type: integer, minimum: 0, description: How many items of reference material the facet holds. }
            updated_at: { type: string, format: date-time, description: When the material last changed. }
        provider_bindings:
          type: array
          items: { $ref: "#/components/schemas/ProviderBinding" }
          description: |
            Copies of the facet held at model providers. Shown only to that provider and to
            licensees whose license includes `material_access` for the facet.
        created_at: { type: string, format: date-time, description: When the facet was created. }
        updated_at:
          type: string
          format: date-time
          description: When the facet's material, status or provider bindings last changed.
    FacetList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Facet" }
              description: The facets on this page, newest first.
    FacetMaterial:
      type: object
      required: [object, facet, license, expires_at, items, obligations]
      properties:
        object: { type: string, const: facet_material, description: Always `facet_material`. }
        facet: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$", description: The facet the material belongs to. }
        license:
          type: string
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: The license that grants material access, as sent in `license`.
        expires_at: { type: string, format: date-time, description: "When the URLs stop working." }
        items:
          type: array
          items:
            type: object
            required: [id, kind, media_type, sha256, size, url]
            properties:
              id: { type: string, pattern: "^mat_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier of the item, prefixed `mat_`." }
              kind:
                type: string
                enum: [reference_image, reference_video, voice_sample, document]
                description: "What the item is: a still, a video clip, a voice sample or a document."
              media_type:
                type: string
                description: The item's MIME type, such as `image/jpeg` or `audio/wav`.
              sha256:
                $ref: "#/components/schemas/Sha256Hex"
                description: |
                  SHA-256 of the item's bytes, in hex. Send exactly these bytes to the model.
              size: { type: integer, description: "Bytes." }
              width: { type: integer, description: "Width in pixels, for images and video." }
              height: { type: integer, description: "Height in pixels, for images and video." }
              duration_ms: { type: integer, description: "Length in milliseconds, for audio and video." }
              url:
                type: string
                format: uri
                description: |
                  Where to download the item until `expires_at`. Every download is recorded on the
                  talent's record.
          description: Every item of the facet's reference material, each with its download URL.
        obligations:
          type: array
          description: What you must do with the material, such as delete it after use.
          items: { $ref: "#/components/schemas/Obligation" }

    # ---------- Resolutions ----------
    ResolutionCreate:
      type: object
      required: [inputs]
      properties:
        inputs:
          type: array
          minItems: 1
          maxItems: 64
          items: { $ref: "#/components/schemas/Input" }
          description: The parts of the request, in order, as you would send them on a check.
        modality:
          $ref: "#/components/schemas/Modality"
          description: What the model will generate, as in a check's `use.modality`.
        exclude_talent:
          type: array
          items: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
          description: |
            Talent your user confirmed they did not mean. They are left out of `candidates`.
    Resolution:
      type: object
      required: [id, object, livemode, status, candidates, use_kind, created_at]
      properties:
        id: { type: string, pattern: "^res_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier, prefixed `res_`." }
        object: { type: string, const: resolution, description: Always `resolution`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        status:
          type: string
          enum: [matched, ambiguous, none]
          description: "`ambiguous`: more than one candidate, or one weak candidate. `none`: no protected talent found, which is not permission."
        candidates:
          type: array
          items:
            type: object
            required: [talent, name, matched_by, confidence]
            properties:
              talent:
                type: string
                pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$"
                description: |
                  The candidate's talent ID. Send it in a check's `talent` or `exclude_talent`.
              name: { type: string, description: "The talent's confirmed name, to show your user." }
              matched_by:
                type: string
                enum: [explicit, name, alias, indirect, reference_image, voice_sample]
                description: |
                  How the inputs invoke the talent. `indirect`: through a confirmed credit or role,
                  such as "the host of Ridge Runners".
              confidence:
                type: string
                enum: [exact, high, medium, low]
                description: |
                  How strong the match is. A check treats every candidate at `medium` or higher as
                  invoked.
              span:
                type: [object, "null"]
                description: Where in the inputs the match is, as zero-based code-point offsets in that input's `text`; `end` is exclusive.
                properties:
                  input: { type: integer, description: "Index in `inputs`." }
                  start: { type: integer, description: Offset of the first matched code point. }
                  end: { type: integer, description: Offset just past the last matched code point. }
                  text: { type: string, description: "The matched text, as it appears in the input." }
              licensed: { type: boolean, description: "Whether the licensee holds an active license for this talent." }
              declaration:
                $ref: "#/components/schemas/Declaration"
                description: The talent's public answer for this use, from their posture.
          description: |
            Each talent the inputs may invoke, including every match at `medium` confidence or
            higher. Empty when `status` is `none`.
        use_kind:
          allOf: [{ $ref: "#/components/schemas/UseKind" }]
          description: How the inputs use the talent. A classification for routing, not a legal finding.
        created_at: { type: string, format: date-time, description: When the resolution was made. }

    # ---------- Licenses ----------
    LicenseStatus:
      type: string
      description: |
        `pending_acceptance`: signed on the talent's side, waiting for the licensee. `scheduled`:
        accepted, window not started. `active`: in force. `suspended`: paused by the talent or a
        representative. `expired`: the window ended. `declined`: the licensee declined it.
        `revoked`: ended by the talent or a representative. `void`: voided in the issuing system;
        the license grants no use. The test-mode status filter does not accept `void`.
      enum: [pending_acceptance, scheduled, active, suspended, expired, declined, revoked, void]
    AdjustmentKind:
      type: string
      description: A change the licensee may make to the talent's appearance or context.
      enum: [reframe, background_extension, lighting, text_overlay, body_and_age, expression, hair, pose, wardrobe, objects, skin_retouch, endorsement]
    ProtectedAttribute:
      type: string
      description: Something every output must keep. `identity.samePerson` is always required.
      enum:
        - identity.samePerson
        - composition.reframe
        - composition.background
        - appearance.lighting
        - context.textOverlay
        - appearance.bodyAndAge
        - appearance.expression
        - appearance.hair
        - appearance.pose
        - appearance.wardrobe
        - context.objects
        - appearance.skinRetouch
        - context.endorsement
    Money:
      type: object
      required: [amount, currency]
      properties:
        amount: { type: integer, description: "In the currency's smallest unit, such as cents." }
        currency: { type: string, pattern: "^[a-z]{3}$", description: "ISO 4217, lowercase." }
    Compensation:
      type: object
      description: What the licensee owes the talent. Reflections computes statements from it and never moves money.
      required: [type]
      properties:
        type:
          type: string
          enum: [none, flat, per_unit, revenue_share]
          description: |
            How the amount owed is set: `none` owes nothing, `flat` is a fixed fee, `per_unit` is a
            rate per unit of usage, and `revenue_share` is `revenue_share_bps` of revenue.
        flat: { $ref: "#/components/schemas/Money", description: "The fixed fee, for `type: flat`." }
        per_unit:
          type: object
          description: "The rate, for `type: per_unit`."
          properties:
            units:
              type: string
              enum: [outputs, seconds, characters, placements, impressions]
              description: |
                What the rate counts. Reflections observes outputs, seconds and characters itself;
                placements and impressions come from usage you report.
            rate: { $ref: "#/components/schemas/Money", description: The amount owed for each `per` units. }
            per: { type: integer, default: 1, description: "The rate is for this many units, such as 1000 impressions." }
        revenue_share_bps: { type: integer, minimum: 0, maximum: 10000, description: "Basis points of revenue the license names." }
        minimum: { $ref: "#/components/schemas/Money", description: "The least the licensee owes, however little is used." }
        schedule:
          type: string
          enum: [on_acceptance, monthly, quarterly]
          description: "When the licensee pays: once on acceptance, each month, or each quarter."
    LicenseScope:
      type: object
      description: |
        The license's terms in normalized, snake_case form. Generated from the signed `terms`;
        when they disagree, `terms` wins. Live license reads currently return only `window`,
        `required_attributes`, `release_policy` and `final_deliverables`, plus `external_creation`
        only when that grant is explicitly signed. Omitted fields grant
        nothing; this partial projection is not the complete signed document.
      properties:
        facets:
          type: array
          items: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$" }
          description: |
            The facets the license covers, by ID. A use of any other facet denies with
            `facet_not_licensed`.
        modalities:
          type: array
          items: { $ref: "#/components/schemas/Modality" }
          description: |
            What may be generated under the license. Any other modality denies with
            `modality_not_licensed`.
        kinds:
          type: array
          items: { $ref: "#/components/schemas/UseKind" }
          description: |
            How the talent may appear in outputs. Any other kind denies with `kind_not_licensed`.
        purposes:
          type: array
          items: { $ref: "#/components/schemas/Purpose" }
          description: |
            What outputs may be used for. Any other purpose denies with `purpose_not_licensed`.
        commercial:
          type: boolean
          description: |
            Whether commercial use is licensed. When `false`, a commercial use denies with
            `commercial_use_not_licensed`.
        channels:
          type: array
          items: { $ref: "#/components/schemas/Channel" }
          description: |
            Where outputs may appear. A use that names any other channel denies with
            `channel_not_licensed`. From `terms.channels`.
        territories:
          type: array
          items: { $ref: "#/components/schemas/Territory" }
          description: |
            Where outputs may appear, as ISO 3166-1 alpha-2 codes or `WW`. A use that names any
            other territory denies with `territory_not_licensed`. From `terms.territories`.
        window:
          type: object
          description: |
            When the license is in force. From `terms.startsAt`, `terms.endsAt` and
            `terms.windowTimeZone`.
          properties:
            starts_at:
              type: string
              format: date-time
              description: |
                When the license comes into force. Before it, checks deny with `window_not_started`.
            ends_at:
              type: string
              format: date-time
              description: |
                When the license ends. From then, checks deny with `window_ended` and the license is
                `expired`.
            time_zone: { type: [string, "null"], description: "The IANA time zone the window's days were signed in." }
        adjustments:
          type: object
          description: Each adjustment and whether it is allowed. From `terms.adjustments`.
          additionalProperties: false
          properties:
            reframe: { type: boolean, description: "`true` allows cropping or reframing the composition." }
            background_extension: { type: boolean, description: "`true` allows extending or replacing the background." }
            lighting: { type: boolean, description: "`true` allows changing the lighting." }
            text_overlay: { type: boolean, description: "`true` allows adding text over the output." }
            body_and_age:
              type: boolean
              description: "`true` allows changing the talent's body or apparent age."
            expression: { type: boolean, description: "`true` allows changing the talent's facial expression." }
            hair: { type: boolean, description: "`true` allows changing the talent's hair." }
            pose: { type: boolean, description: "`true` allows changing the talent's pose." }
            wardrobe: { type: boolean, description: "`true` allows changing what the talent wears." }
            objects: { type: boolean, description: "`true` allows adding or changing objects in the scene." }
            skin_retouch: { type: boolean, description: "`true` allows retouching the talent's skin." }
            endorsement:
              type: boolean
              description: "`true` allows outputs that imply the talent endorses something."
        prohibited_changes:
          type: array
          items: { $ref: "#/components/schemas/AdjustmentKind" }
          description: Adjustments that are never allowed. From `terms.prohibitedChanges`.
        required_attributes:
          type: array
          items: { $ref: "#/components/schemas/ProtectedAttribute" }
          description: |
            What every output must keep, checked on the output bytes. Always includes
            `identity.samePerson`. From `terms.requiredAttributes`.
        rules:
          type: object
          description: Rules the talent wrote, as written. From `terms.neverExtras`, `terms.alwaysExtras` and `terms.creationBrief`.
          properties:
            never:
              type: array
              items: { type: string, maxLength: 160 }
              description: |
                What outputs must never show or say, as the talent wrote it, up to 160 characters
                each. From `terms.neverExtras`.
            always:
              type: array
              items: { type: string, maxLength: 160 }
              description: |
                What every output must show or keep, as the talent wrote it, up to 160 characters
                each. From `terms.alwaysExtras`.
            brief:
              type: [string, "null"]
              maxLength: 160
              description: |
                The talent's brief for outputs, as written. `null` if none. From
                `terms.creationBrief`.
        external_creation:
          type: string
          enum: [images.v1]
          description: |
            The exact signed `terms.externalCreation` grant, when present. `images.v1` is prospective
            permission for still images made in the licensee's tools using inputs it lawfully holds,
            subject to request and output checks and mandatory talent release. It grants no export
            of private references, their identifiers or source bytes. Absence grants nothing; this
            value is never inferred from `make`, a creation profile or `offPlatformProduction`.
            This is reader support only: issuance cannot add this term yet, and live checks,
            output submission and receipts remain unavailable.
        release_policy:
          type: string
          enum: [after_checks, per_output_review]
          description: |
            `after_checks`: an output that passes its checks is allowed. `per_output_review`: a
            person releases each output. From `terms.releasePolicy` (`dualCheckBrandRelease`,
            `perOutputTalentReview`).
        escalation_window:
          $ref: "#/components/schemas/Duration"
          description: |
            How long an escalation under the license waits for a decision, when shorter than the
            default 7 days.
        final_deliverables: { type: [integer, "null"], minimum: 1, description: "Outputs that may be delivered under the license in total." }
        monthly_limits:
          type: [object, "null"]
          description: |
            Caps on use per month. Past one, checks deny with `monthly_limit_reached`. `null` when
            the license sets none.
          properties:
            outputs: { type: integer, description: Outputs per month. }
            seconds: { type: integer, description: Seconds of generated audio or video per month. }
            characters: { type: integer, description: Characters of generated text or speech per month. }
            asks: { type: integer, description: "Knowledge questions per month. From `terms.knowledgeGrant.asksPerMonth`." }
        sessions:
          type: object
          description: Whether live sessions may run, and how they are sampled.
          properties:
            permitted:
              type: boolean
              description: |
                Whether live sessions may run under the license. When `false`, or when
                `release_policy` is `per_output_review`, a session is denied with
                `session_not_permitted`.
            sampling:
              $ref: "#/components/schemas/Sampling"
              description: |
                How each session must be sampled: the longest audio window, transcripts, and the
                frame interval for video.
        material_access:
          type: array
          description: Facets whose reference material the licensee may download and send to a model.
          items: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$" }
        knowledge:
          type: [object, "null"]
          description: From `terms.knowledgeGrant`.
          properties:
            volume_title: { type: string, description: The title of the Volume a model may draw on. }
            answers:
              type: string
              enum: [summarised, quoted]
              description: |
                `summarised`: answers paraphrase the Volume. `quoted`: answers may quote it.
            about:
              type: array
              items: { type: string }
              description: Topics a model may answer from the Volume.
            never:
              type: array
              items: { type: string }
              description: Topics a model must never answer.
        platforms:
          type: object
          description: Which platforms may run checks under this license.
          properties:
            mode:
              type: string
              enum: [any_connected, listed]
              description: |
                `any_connected`: any platform the licensee connects. `listed`: only the accounts in
                `accounts`.
            accounts:
              type: array
              items: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$" }
              description: |
                The platforms that may run checks when `mode` is `listed`. Empty for
                `any_connected`.
        sublicense:
          type: string
          enum: [none, end_users_personal]
          description: "`end_users_personal`: a platform's end users may make personal, non-commercial outputs under the platform's license."
        training:
          type: string
          enum: [prohibited, permitted]
          default: prohibited
          description: |
            Whether covered material and outputs may train a model. `prohibited` puts a
            `no_training` obligation on each use. Recorded, not enforced.
        disclosure:
          type: string
          enum: [nothing, licensed, brand, scope]
          description: The label outputs carry. `licensed` says the likeness is licensed; `brand` adds who licensed it; `scope` adds the use.
        attribution:
          type: [string, "null"]
          description: |
            A credit line each output must show, delivered as an `attribution` obligation. `null`
            when the license requires none. Recorded, not enforced.
        post_revocation:
          type: object
          description: What happens to released outputs if the license is revoked.
          properties:
            policy:
              type: string
              enum: [retain, cease_distribution, withdraw]
              description: |
                `retain`: released outputs stay usable within their scope and window.
                `cease_distribution`: no new placements after the revocation. `withdraw`: take them
                down within `withdraw_within`; only for revocation for cause.
            withdraw_within:
              $ref: "#/components/schemas/Duration"
              description: |
                For `withdraw`, how long platforms have to take released outputs down after a
                revocation for cause.
        exclusivity:
          type: [object, "null"]
          description: Recorded, not enforced.
          properties:
            exclusive:
              type: boolean
              description: |
                Whether the talent agreed to exclusivity, within `category` when one is named. From
                `terms.isExclusive`.
            category:
              type: [string, "null"]
              enum: [beauty_and_skincare, fashion, spirits, autos, finance, technology, wellness_and_pharma, gaming, travel, null]
              description: |
                The product category the exclusivity covers. `null` when it names no category or the
                license is not exclusive.
        conflicts:
          type: array
          description: Brands the talent is not to be associated with during the license. Recorded, not enforced.
          items:
            type: object
            properties:
              name: { type: string, description: The brand's name. }
              category:
                type: [string, "null"]
                description: The brand's product category, such as `spirits`. `null` if not given.
        compensation:
          $ref: "#/components/schemas/Compensation"
          description: "What the licensee owes the talent. Recorded: statements are computed from it."
    LicenseScopeRequest:
      type: object
      description: The scope you ask for. Omitted fields ask for nothing beyond the current license, or for the talent's defaults.
      properties:
        facets:
          type: array
          items: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$" }
          description: The facets you ask for, by ID.
        facet_types:
          type: array
          items: { $ref: "#/components/schemas/FacetType" }
          description: |
            The facet types you ask for, such as `likeness`, when you do not name `facets`.
        modalities:
          type: array
          items: { $ref: "#/components/schemas/Modality" }
          description: What you want to generate.
        kinds:
          type: array
          items: { $ref: "#/components/schemas/UseKind" }
          description: How the talent would appear.
        purposes:
          type: array
          items: { $ref: "#/components/schemas/Purpose" }
          description: What the outputs are for.
        commercial: { type: boolean, description: "`true` to ask for commercial use." }
        channels:
          type: array
          items: { $ref: "#/components/schemas/Channel" }
          description: |
            Where outputs would appear. For `change`, list every channel you want, not only the new
            ones.
        territories:
          type: array
          items: { $ref: "#/components/schemas/Territory" }
          description: Where outputs would appear, as ISO 3166-1 alpha-2 codes or `WW`.
        starts_at: { type: string, format: date-time, description: When you want the license to come into force. }
        ends_at: { type: string, format: date-time, description: When you want the license to end. }
        adjustments:
          type: array
          description: Adjustments you ask to be allowed.
          items: { $ref: "#/components/schemas/AdjustmentKind" }
        final_deliverables: { type: integer, minimum: 1, description: How many outputs you want to deliver in total. }
        sessions: { type: boolean, description: "Ask for live sessions." }
        material_access:
          type: boolean
          description: |
            `true` to ask to download the facets' reference material and send it to a model.
        platforms:
          type: array
          items: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$" }
          description: Platform accounts you want to run checks under the license.
        sublicense:
          type: string
          enum: [none, end_users_personal]
          description: |
            `end_users_personal` to ask that a platform's end users may make personal,
            non-commercial outputs.
    TermEnforcement:
      type: object
      required: [term, enforcement]
      properties:
        term:
          $ref: "#/components/schemas/Address"
          description: The term, as an address such as `license:lic_…/terms.channels`.
        enforcement:
          type: string
          enum: [checked, recorded]
          description: "`checked`: Reflections enforces it at the check or the generation. `recorded`: signed and shown, not enforced."
        stage:
          type: array
          items: { type: string, enum: [check, generation, session] }
          description: Where a `checked` term is enforced. Empty for a `recorded` term.
    Signature:
      type: object
      required: [party, signed_at, method]
      properties:
        party:
          type: string
          enum: [talent, representative, licensee]
          description: |
            Who signed: the `talent`, a `representative` with `issue_licenses`, or the `licensee`
            when it accepted.
        account:
          type: [string, "null"]
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The account that signed, for a `representative` or the `licensee`. `null` when the
            talent signed.
        name:
          type: string
          description: |
            The name signed under: a person's name on the talent's side, the account's name for the
            licensee.
        method: { type: string, enum: [passkey], description: "The signer confirmed with a passkey bound to their verified account." }
        signed_at: { type: string, format: date-time, description: When the signer confirmed with their passkey. }
    License:
      type: object
      required: [id, object, livemode, status, talent, licensee, handle, current_revision, revision_number, scope, created_at]
      properties:
        id: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier for the license, `lic_…`." }
        object: { type: string, const: license, description: Always `license`. }
        livemode: { type: boolean, description: "`true` for a live-mode license, `false` for a test-mode one." }
        status:
          $ref: "#/components/schemas/LicenseStatus"
          description: |
            Where the license is in its life. Checks are decided on its terms only while it is
            `active`; under every other status they deny.
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent who granted the license. }
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: The account that holds the license and answers for every use made under it.
        issued_by:
          type: object
          description: Who signed the first revision.
          properties:
            party:
              type: string
              enum: [talent, representative]
              description: |
                `talent` when the talent signed, or `representative` when a representative with
                `issue_licenses` signed for them.
            account:
              type: [string, "null"]
              pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
              description: The representative's account. `null` when the talent signed.
            mandate: { type: [string, "null"], pattern: "^mnd_[0-9a-hjkmnp-tv-z]{26}$", description: "The mandate a representative signed under." }
            draft: { type: [string, "null"], pattern: "^ldr_[0-9a-hjkmnp-tv-z]{26}$", description: "The draft the license was signed from, if any." }
        handle:
          type: string
          pattern: "^[0-9BCDFGHJKMNPQRSTVWXYZ]{6}$"
          description: A six-character name for the license that people can read aloud, such as `K7Q4M2`.
        current_revision: { type: string, pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$", description: "The revision in force. While the license is `pending_acceptance`, the first revision, waiting to be accepted." }
        revision_number: { type: integer, minimum: 1, description: "The `number` of `current_revision`, starting at 1." }
        pending_revision:
          type: [string, "null"]
          pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            A new revision the talent's side signed, such as a change the licensee requested, an
            amendment or a renewal, waiting for the licensee to accept it at `acceptance_url`.
            `current_revision` stays in force until then.
        terms_digest:
          $ref: "#/components/schemas/Digest"
          description: |
            The digest of the current revision's signed `terms`. Checks, authorizations and receipts
            decided under that revision carry the same value. A live read returns the digest of
            the full signed terms, not a digest of the partial `scope`; live revision retrieval
            and live decision endpoints remain planned.
        scope:
          $ref: "#/components/schemas/LicenseScope"
          description: |
            The terms of `current_revision` in normalized form. A pending revision does not change
            it until the licensee accepts.
        acceptance_url:
          type: [string, "null"]
          format: uri
          description: The hosted page where the licensee reads and accepts the license, or its `pending_revision`. Present while `pending_acceptance`, and while a revision is pending.
        accepted_at: { type: [string, "null"], format: date-time, description: When the licensee accepted the license. `null` until then. }
        suspended_at:
          type: [string, "null"]
          format: date-time
          description: When the current suspension began. `null` unless the license is `suspended`.
        revoked_at: { type: [string, "null"], format: date-time, description: When the license was revoked. `null` unless it is `revoked`. }
        declined_at:
          type: [string, "null"]
          format: date-time
          description: When the licensee declined the license. `null` unless it is `declined`.
        metadata: { $ref: "#/components/schemas/Metadata", description: Key-value pairs stored on the license. }
        created_at: { type: string, format: date-time, description: When the talent's side signed the first revision. }
    LicenseList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/License" }
              description: The licenses on this page, newest first.
    LicenseRevisionStatus:
      type: string
      description: |
        `pending_acceptance`: signed on the talent's side, waiting for the licensee. `current`: in
        force; the license's `current_revision`. `superseded`: a later revision became current.
        `declined`: the licensee declined it.
      enum: [pending_acceptance, current, superseded, declined]
    LicenseRevision:
      type: object
      required: [id, object, livemode, license, number, status, source_kind, terms, terms_digest, canonicalization, scope, enforcement, signatures, created_at]
      properties:
        id: { type: string, pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier for the revision, `lrv_…`." }
        object: { type: string, const: license_revision, description: Always `license_revision`. }
        livemode:
          type: boolean
          description: "`true` for a live-mode revision, `false` for a test-mode one."
        license: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: The license the revision belongs to. }
        number:
          type: integer
          minimum: 1
          description: |
            The revision's position in its license, from 1 for the revision signed with the license.
        status:
          $ref: "#/components/schemas/LicenseRevisionStatus"
          description: |
            Where the revision stands. New checks are decided under the `current` revision only.
        source_kind:
          type: string
          enum: [issue, change_request, amend, renew]
          description: |
            What produced the revision. `issue`: signed with the license. `change_request`: a change
            the licensee asked for. `amend`: an amendment from the talent's side. `renew`: a
            renewal, such as a new window.
        terms:
          type: object
          additionalProperties: true
          description: |
            The signed document, exactly as signed, with its own camelCase field names. Its
            canonical form digests to `terms_digest`.
        terms_digest:
          $ref: "#/components/schemas/Digest"
          description: |
            `sha256:` and the hex SHA-256 of `terms` in `tlp-json-1` canonical form. Recompute it to
            confirm you hold the signed document.
        canonicalization:
          type: string
          const: tlp-json-1
          description: "The canonical JSON form the digest is computed over: UTF-8, object keys sorted by code point, no insignificant whitespace. Defined in the Standard under Tokens, canonical form."
        scope:
          $ref: "#/components/schemas/LicenseScope"
          description: |
            `terms` in normalized, snake_case form, for your code to read. Hash `terms`, never
            `scope`.
        enforcement:
          type: array
          items: { $ref: "#/components/schemas/TermEnforcement" }
          description: |
            Each term with its class: `checked` terms are enforced at the stages listed, `recorded`
            terms are signed and shown only.
        signatures:
          type: array
          description: The talent's side signs first. The licensee's signature is added when it accepts.
          items: { $ref: "#/components/schemas/Signature" }
        document_url: { type: string, format: uri, description: "The signed document as a person reads it." }
        created_at: { type: string, format: date-time, description: When the talent's side signed the revision. }
    LicenseRevisionList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/LicenseRevision" }
              description: The revisions on this page, newest first, whatever their `status`.

    # ---------- License requests ----------
    LicenseRequestStatus:
      type: string
      description: "`sent`: waiting for the talent's side. `signed`: the talent's side signed a license from it. `declined`: the talent's side declined. `withdrawn`: you withdrew it."
      enum: [sent, signed, declined, withdrawn]
    LicenseRequestCreate:
      type: object
      required: [kind, talent, requested_scope]
      properties:
        kind:
          type: string
          enum: [new, change]
          description: |
            `new` for a new license, or `change` for a new revision of the license in `license`,
            such as a wider scope.
        talent:
          type: string
          pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The talent to ask. A talent whose `posture.accepts_requests` is `false` takes no
            requests through the API.
        license: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: Required for `change`. }
        check:
          type: string
          pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$"
          description: The denied check this request answers. The talent sees the use that prompted it.
        requested_scope:
          $ref: "#/components/schemas/LicenseScopeRequest"
          description: |
            The terms you ask for. A denied check's `remedy.suggested_scope` is a starting point.
            For `change`, omitted fields keep the current license's terms.
        offer:
          $ref: "#/components/schemas/Compensation"
          description: What you offer to pay. The talent's side may sign different compensation.
        note: { type: string, maxLength: 2000, description: "Shown to the talent as written." }
        metadata: { $ref: "#/components/schemas/Metadata", description: "Your own key-value pairs, returned on the request." }
    LicenseRequest:
      type: object
      required: [id, object, livemode, kind, status, talent, licensee, requested_scope, created_at]
      properties:
        id: { type: string, pattern: "^lrq_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier for the request, `lrq_…`." }
        object: { type: string, const: license_request, description: Always `license_request`. }
        livemode: { type: boolean, description: "`true` for a live-mode request, `false` for a test-mode one." }
        kind:
          type: string
          enum: [new, change]
          description: "`new` for a new license, or `change` for a new revision of `license`."
        status:
          $ref: "#/components/schemas/LicenseRequestStatus"
          description: Where the request stands. Only a `sent` request can be withdrawn or declined.
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent the request asks. }
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The account that would hold the license: the sender, or the connected licensee a
            platform sent it for.
        license:
          type: [string, "null"]
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: For `change`, the license to change. When signed, the license it became.
        license_revision:
          type: [string, "null"]
          pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$"
          description: The revision the talent's side signed. It may differ from what you asked.
        check:
          type: [string, "null"]
          pattern: "^chk_[0-9a-hjkmnp-tv-z]{26}$"
          description: The denied check that prompted the request. `null` if none was named.
        requested_scope: { $ref: "#/components/schemas/LicenseScopeRequest", description: "The terms asked for, as sent." }
        offer:
          description: The compensation offered. `null` if the request made no offer.
          oneOf:
            - $ref: "#/components/schemas/Compensation"
            - type: "null"
        note: { type: [string, "null"], description: "The note to the talent, as written. `null` if none was sent." }
        decision_note: { type: [string, "null"], description: "The talent's note when they declined or signed." }
        signed_at:
          type: [string, "null"]
          format: date-time
          description: |
            When the talent's side signed a license or revision from the request. `null` unless
            `signed`.
        declined_at:
          type: [string, "null"]
          format: date-time
          description: When the talent's side declined the request. `null` unless `declined`.
        withdrawn_at:
          type: [string, "null"]
          format: date-time
          description: When the licensee withdrew the request. `null` unless `withdrawn`.
        metadata: { $ref: "#/components/schemas/Metadata", description: The key-value pairs sent with the request. }
        created_at: { type: string, format: date-time, description: When the request was sent. }
    LicenseRequestList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/LicenseRequest" }
              description: The requests on this page, newest first.
    ConnectionCreate:
      type: object
      required: [code, code_verifier, redirect_uri]
      properties:
        code:
          type: string
          maxLength: 256
          description: The `code` your redirect URI received.
        code_verifier:
          type: string
          minLength: 43
          maxLength: 128
          description: The PKCE verifier whose `S256` challenge you sent to the authorization endpoint.
        redirect_uri:
          type: string
          format: uri
          description: The redirect URI you sent to the authorization endpoint, character for character.

    # ---------- Connections ----------
    Connection:
      type: object
      required: [id, object, livemode, status, licensee, platform, scopes, licenses, created_at]
      properties:
        id: { type: string, pattern: "^con_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier for the connection, `con_…`." }
        object: { type: string, const: connection, description: Always `connection`. }
        livemode:
          type: boolean
          description: "`true` for a live-mode connection, `false` for a test-mode one."
        status:
          type: string
          enum: [active, revoked]
          description: |
            `active` while the platform may act for the licensee. `revoked` once the licensee, the
            platform or Reflections ended it.
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The account whose licenses the platform may use. Send it in `Reflections-Account`.
        licensee_name: { type: string, description: The licensee's account name. }
        platform: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The platform account that acts for the licensee. }
        platform_name:
          type: string
          description: The platform's `display_name`, as the licensee saw it when approving.
        scopes:
          type: array
          items:
            type: string
            enum: [talent:read, licenses:read, license_requests:write, files:write, checks:write, generations:write, sessions:write, revocations:write, usage:write, statements:read]
          description: |
            What the platform may do for the licensee, as approved through OAuth. A call that needs
            a scope not listed fails with `403 account_not_connected`.
        licenses:
          type: object
          description: Which of the licensee's licenses the platform may use.
          properties:
            mode:
              type: string
              enum: [all, listed]
              description: |
                `all`: every license the licensee holds. `listed`: only the licenses in `ids`.
            ids:
              type: array
              items: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
              description: |
                The licenses the platform may use when `mode` is `listed`. Empty for `all`.
        revoked_by: { type: [string, "null"], enum: [licensee, platform, reflections, null], description: Who ended the connection. `null` while it is `active`. }
        revoked_at:
          type: [string, "null"]
          format: date-time
          description: |
            When the connection ended. From then, calls for the licensee fail with
            `account_not_connected`. `null` while it is `active`.
        created_at: { type: string, format: date-time, description: When the licensee approved the connection. }
    ConnectionList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Connection" }
              description: The connections on this page, newest first.

    # ---------- Files ----------
    FilePurpose:
      type: string
      description: "`reference` and `voice_sample`: media a model receives. `mask`: an edit mask. `output`: something a model made, to submit as a generation."
      enum: [reference, voice_sample, mask, output]
    FileCreate:
      type: object
      description: Create a file and upload its bytes to `upload_url`. For files over 100 MB, up to 5 GB.
      required: [purpose, size, sha256, media_type]
      properties:
        purpose:
          $ref: "#/components/schemas/FilePurpose"
          description: "What the file is for: media a model receives, or an output to submit."
        size: { type: integer, minimum: 1, maximum: 5368709120, description: "Size in bytes, up to 5 GB." }
        sha256:
          $ref: "#/components/schemas/Sha256Hex"
          description: |
            SHA-256 of the bytes you will upload, in hex. Bytes that do not match are refused with
            `artifact_digest_mismatch`.
        media_type: { type: string, description: "The file's MIME type, such as `video/mp4`." }
        filename: { type: string, maxLength: 255, description: "Your name for the file, such as `ridge-trail.mp4`." }
    File:
      type: object
      required: [id, object, livemode, purpose, status, sha256, media_type, size, expires_at, created_at]
      properties:
        id:
          type: string
          pattern: "^file_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            Unique identifier, prefixed `file_`. Send it as an input's `file` or an artifact's
            `file`.
        object: { type: string, const: file, description: Always `file`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        purpose:
          $ref: "#/components/schemas/FilePurpose"
          description: "What the file is for: media a model receives, or an output to submit."
        status:
          type: string
          enum: [uploading, ready, expired]
          description: |
            `uploading`: waiting for the bytes at `upload_url`. `ready`: usable in checks and
            generations. `expired`: deleted; upload it again.
        sha256: { $ref: "#/components/schemas/Sha256Hex", description: "SHA-256 of the file's bytes, in hex." }
        media_type: { type: string, description: The file's MIME type. }
        size: { type: integer, description: Size in bytes. }
        width:
          type: [integer, "null"]
          description: |
            Width in pixels, for images and video. `null` for other files, and until the bytes
            arrive.
        height:
          type: [integer, "null"]
          description: |
            Height in pixels, for images and video. `null` for other files, and until the bytes
            arrive.
        duration_ms:
          type: [integer, "null"]
          description: |
            Length in milliseconds, for audio and video. `null` for other files, and until the bytes
            arrive.
        upload_url:
          type: [string, "null"]
          format: uri
          description: "`PUT` the bytes here. Present while `uploading`; expires in 1 hour."
        expires_at:
          type: string
          format: date-time
          description: |
            When the file is deleted: 24 hours after it was created, or later while a held
            generation needs it.
        created_at: { type: string, format: date-time, description: When the file was created. }

    # ---------- Receipts and verification ----------
    UseStatus:
      type: string
      description: |
        What use of the output is permitted now. `permitted`: within the receipt's scope.
        `ceased`: no new placements, after a revocation. `withdrawn`: take it down. `expired`:
        the use window ended.
      enum: [permitted, ceased, withdrawn, expired]
    Receipt:
      type: object
      required: [id, object, livemode, kind, subject, decision, assurance, talent, licenses, jws, use_status, issued_at]
      properties:
        id:
          type: string
          pattern: "^rcpt_[0-9a-hjkmnp-tv-z]{26}$"
          description: Unique identifier, prefixed `rcpt_`. The JWS carries it as `jti`.
        object: { type: string, const: receipt, description: Always `receipt`. }
        livemode:
          type: boolean
          description: |
            `false` for a test-mode receipt, signed with a test key. It verifies only with a test
            key.
        kind: { type: string, enum: [check, generation], description: Whether `subject` is a check or a generation. }
        subject: { type: string, description: "The check or generation ID." }
        decision:
          type: string
          enum: [allow, deny]
          description: A receipt records a final decision. An escalated check or output gets its receipt when it is decided.
        assurance:
          type: string
          enum: [observed, attested]
          description: |
            `observed`: Reflections checked these bytes or this request itself. `attested`:
            Reflections recorded what the platform stated, such as text sent `withheld`.
        talent:
          type: array
          description: Every talent the decision covers.
          items: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$" }
        licenses:
          type: array
          description: |
            The signed terms the decision relied on, one entry per talent whose license applied, in
            the order of `talent`. Empty when no license applied, as for a check whose inputs
            invoke no talent, or a `deny` with `no_license`.
          items: { $ref: "#/components/schemas/ReceiptLicense" }
        licensee:
          type: [string, "null"]
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: The account whose license applied. `null` when no license applied.
        platform: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The platform that made the request. }
        request_digest:
          allOf: [{ $ref: "#/components/schemas/Digest" }]
          description: The request digest of the check, or for a generation, of the check it was made under.
        artifact_sha256:
          description: |
            SHA-256, in hex, of the bytes submitted to the generation, before any C2PA manifest was
            embedded. `null` on a check receipt.
          oneOf:
            - $ref: "#/components/schemas/Sha256Hex"
            - type: "null"
        permitted_use:
          type: [object, "null"]
          description: The use the receipt covers.
          properties:
            modality: { $ref: "#/components/schemas/Modality", description: What was generated. }
            purpose: { $ref: "#/components/schemas/Purpose", description: The purpose the use covers. }
            channels:
              type: array
              items: { $ref: "#/components/schemas/Channel" }
              description: Where the output may appear.
            territories:
              type: array
              items: { $ref: "#/components/schemas/Territory" }
              description: Where the output may be shown, as country codes or `WW` for worldwide.
            ends_at:
              type: [string, "null"]
              format: date-time
              description: |
                When the use window ends; `use_status` then becomes `expired`. `null` when the use
                has no end date.
        obligations:
          type: array
          items: { $ref: "#/components/schemas/Obligation" }
          description: The obligations the decision carried, with all their fields.
        use_status:
          oneOf:
            - $ref: "#/components/schemas/UseStatus"
            - type: "null"
          description: Whether the output may still be used. `null` on a `deny` receipt, which permits nothing.
        use_status_changed_at: { type: [string, "null"], format: date-time, description: When `use_status` last changed. `null` if it never has. }
        jws: { type: string, description: "The signed receipt, a compact JWS with `typ` `tlp-receipt+jwt`." }
        cose: { type: string, contentEncoding: base64, description: "The same claims as a tagged COSE_Sign1 structure, for tools that work in CBOR." }
        page_url: { type: string, format: uri, description: "The public receipt page." }
        issued_at:
          type: string
          format: date-time
          description: |
            When the decision was made and the receipt signed. The JWS carries it as `iat`.
    DiscoveryDocument:
      type: object
      required: [issuer, protocol, protocol_versions, api_base, api_versions, jwks_uri, check_endpoint, generation_endpoint, verification_endpoint, receipt_endpoint, revocation_feed, receipt_page, token_types, obligation_types, c2pa_assertion_label]
      properties:
        issuer: { type: string, format: uri, description: "The `iss` of every token and receipt this server signs." }
        protocol: { type: string, const: tlp, description: "Always `tlp`, the Talent License Protocol." }
        protocol_versions: { type: array, items: { type: string }, description: "Talent License Protocol versions, such as `1.0`." }
        api_base: { type: string, format: uri, description: The base URL of the API. }
        api_versions: { type: array, items: { type: string }, description: "Dated versions accepted in `Reflections-Version`." }
        jwks_uri: { type: string, format: uri, description: The JWKS that holds the keys for tokens and receipts. }
        check_endpoint: { type: string, format: uri, description: Where to create a check. }
        generation_endpoint: { type: string, format: uri, description: Where to create a generation. }
        session_endpoint: { type: string, format: uri, description: Where to create a session. }
        verification_endpoint: { type: string, format: uri, description: Where to verify content. }
        receipt_endpoint: { type: string, description: "A URL template with `{receipt_id}`." }
        revocation_feed: { type: string, format: uri, description: The revocation feed. }
        talent_index: { type: string, format: uri, description: The signed name index. }
        authorization_endpoint: { type: string, format: uri, description: "OAuth authorization, for connections and MCP." }
        token_endpoint: { type: string, format: uri, description: OAuth token exchange. }
        introspection_endpoint: { type: string, format: uri, description: "OAuth token introspection, for the RSL Open License Protocol." }
        mcp_endpoint: { type: string, format: uri, description: The MCP server for agents. }
        receipt_page: { type: string, description: "A URL template with `{receipt_id}`." }
        token_types:
          type: array
          items: { type: string, enum: [tlp-auth+jwt, tlp-session+jwt, tlp-receipt+jwt] }
          description: |
            The `typ` of each signed format: authorization token, session token and receipt.
        obligation_types:
          type: array
          items: { $ref: "#/components/schemas/ObligationType" }
          description: Every obligation type this server can issue. Treat any other type as unmet.
        c2pa_assertion_label: { type: string, const: ai.reflections.license, description: The label of the C2PA assertion that carries the receipt. }
    Jwks:
      type: object
      required: [keys]
      properties:
        keys:
          type: array
          items:
            type: object
            required: [kty, crv, kid, use, alg, x, "y"]
            properties:
              kty: { type: string, const: EC, description: Always `EC`. }
              crv: { type: string, const: P-256, description: Always `P-256`. }
              kid: { type: string, description: "Live keys look like `rfl-2026-10-docs3`, test keys like `rfl-test-2026-10-docs3`." }
              use: { type: string, const: sig, description: Always `sig`. }
              alg: { type: string, const: ES256, description: Always `ES256`. }
              x: { type: string, description: "base64url." }
              "y": { type: string, description: "base64url." }
          description: |
            Every key that signs, or once signed, tokens and receipts. Retired keys stay published
            so old receipts keep verifying.

    # ---------- OAuth ----------
    OAuthScope:
      type: string
      description: |
        A scope a person can approve. Connections use all ten. The MCP server accepts
        `talent:read`, `licenses:read`, `checks:write`, `generations:write`,
        `license_requests:write` and `usage:write`.
      enum: [talent:read, licenses:read, license_requests:write, files:write, checks:write, generations:write, sessions:write, revocations:write, usage:write, statements:read]
    AccessTokenCreate:
      description: |
        A token request. Its fields follow from `grant_type`.
      oneOf:
        - title: Authorization code
          type: object
          description: An MCP client redeems a code from the authorization page.
          required: [grant_type, code, redirect_uri, code_verifier]
          properties:
            grant_type: { type: string, enum: [authorization_code], description: "`authorization_code`." }
            code: { type: string, description: The `code` the redirect carried. }
            redirect_uri: { type: string, format: uri, description: The `redirect_uri` sent to the authorization page. }
            code_verifier:
              type: string
              minLength: 43
              maxLength: 128
              description: The PKCE verifier whose S256 hash was the `code_challenge`.
            client_id: { type: string, description: "The client's ID. Required for a public client, which sends no secret." }
            resource:
              type: string
              format: uri
              description: The resource the token is for, as RFC 8707 defines, `https://app.reflections.ai/mcp`.
        - title: Refresh token
          type: object
          description: A client exchanges a refresh token for a new access token and refresh token.
          required: [grant_type, refresh_token]
          properties:
            grant_type: { type: string, enum: [refresh_token], description: "`refresh_token`." }
            refresh_token: { type: string, description: The refresh token to exchange. }
            client_id: { type: string, description: "The client's ID. Required for a public client, which sends no secret." }
            scope:
              type: string
              description: |
                Space-separated scopes to narrow the new token to. Each must be one the person
                approved.
            resource:
              type: string
              format: uri
              description: The resource the token is for, `https://app.reflections.ai/mcp`.
        - title: RSL license token
          type: object
          description: A confidential RSL client requests a `License` token for a talent's facet.
          required: [grant_type, resource, license]
          properties:
            grant_type: { type: string, enum: [client_credentials], description: "`client_credentials`." }
            resource:
              type: string
              format: uri
              description: The `url` of the RSL `<content>` element, which is the facet's IRI.
            license:
              type: string
              description: |
                The complete RSL `<license>` element you request, as XML. It must be one the
                talent's RSL document offers for `resource`.
    AccessToken:
      type: object
      description: An access token, as RFC 6749 returns it.
      required: [access_token, token_type, expires_in, livemode]
      properties:
        access_token:
          type: string
          description: |
            Send a `Bearer` token to the MCP server as `Authorization: Bearer <token>`. Send a
            `License` token to the content host as `Authorization: License <token>`.
        token_type:
          type: string
          enum: [Bearer, License]
          description: "`Bearer` for the MCP server. `License` for an RSL license token."
        expires_in:
          type: integer
          description: |
            Seconds until the access token expires: 3600 for `Bearer`. For `License`, 86400, or less
            when the license it draws on ends sooner.
        refresh_token:
          type: string
          description: |
            For `authorization_code` and `refresh_token` grants. Each use returns a new refresh token
            and ends the old one. A refresh token expires after 30 days unused, or when the person
            removes the client.
        scope:
          type: string
          description: The space-separated scopes the token carries, which the person approved. Absent for `License` tokens.
        livemode:
          type: boolean
          description: |
            `true` when the token acts in live mode. For `Bearer` tokens, the person chose the mode on
            the authorization page.
    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.
    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.
    TokenIntrospectionCreate:
      type: object
      description: An introspection request, as RFC 7662 defines it.
      required: [token]
      properties:
        token: { type: string, description: The token the client presented. }
        token_type_hint:
          type: string
          enum: [access_token]
          description: Optional. A `License` token is an access token.
        resource:
          type: string
          format: uri
          description: |
            The content the token was presented for: the facet IRI, or the URL of a file under it.
            `permitted` in the result is about this resource.
    TokenIntrospection:
      type: object
      description: |
        Whether a token is active, as RFC 7662 returns it. An inactive token returns only `active`.
      required: [active]
      properties:
        active: { type: boolean, description: "`true` while the token is unexpired and the license it draws on is active." }
        token_type: { type: string, enum: [License], description: Always `License`. }
        permitted: { type: boolean, description: "Whether the token covers `resource`. Serve the content only when this and `active` are both `true`." }
        client_id: { type: string, description: The client the token was issued to. }
        resource: { type: string, format: uri, description: "The facet IRI the token was issued for." }
        usage:
          type: array
          items: { type: string }
          description: "The RSL `usage` values the token covers, such as `ai-input`."
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent whose facet the token covers. }
        license:
          type: [string, "null"]
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The license the token draws on. `null` when the talent's posture allows the usage without
            a license.
        livemode: { type: boolean, description: "`true` for a live-mode token." }
        iat: { type: integer, description: Unix seconds when the token was issued. }
        exp: { type: integer, description: Unix seconds when the token expires. }
    TokenRevocationCreate:
      type: object
      description: A revocation request, as RFC 7009 defines it.
      required: [token]
      properties:
        token: { type: string, description: The access or refresh token to revoke. }
        token_type_hint:
          type: string
          enum: [access_token, refresh_token]
          description: Optional. Which kind of token `token` is.
        client_id: { type: string, description: "The client's ID. Required for a public client, which sends no secret." }
    AuthorizationServerMetadata:
      type: object
      description: OAuth authorization server metadata, as RFC 8414 defines it.
      required: [issuer, authorization_endpoint, token_endpoint, response_types_supported, grant_types_supported, code_challenge_methods_supported]
      properties:
        issuer: { type: string, format: uri, description: "The issuer, `https://app.reflections.ai`. It equals the `iss` on every authorization response." }
        authorization_endpoint: { type: string, format: uri, description: The authorization page. }
        token_endpoint: { type: string, format: uri, description: The token endpoint. }
        registration_endpoint: { type: string, format: uri, description: The client registration endpoint. }
        introspection_endpoint: { type: string, format: uri, description: "The introspection endpoint, for RSL content hosts." }
        revocation_endpoint: { type: string, format: uri, description: The revocation endpoint. }
        scopes_supported:
          type: array
          items: { $ref: "#/components/schemas/OAuthScope" }
          description: Every scope a client may ask for.
        response_types_supported:
          type: array
          items: { type: string }
          description: Always `["code"]`.
        response_modes_supported:
          type: array
          items: { type: string }
          description: Always `["query"]`.
        grant_types_supported:
          type: array
          items: { type: string }
          description: The grants the token endpoint accepts.
        token_endpoint_auth_methods_supported:
          type: array
          items: { type: string }
          description: How clients authenticate at the token endpoint.
        introspection_endpoint_auth_methods_supported:
          type: array
          items: { type: string }
          description: How clients authenticate at the introspection endpoint.
        revocation_endpoint_auth_methods_supported:
          type: array
          items: { type: string }
          description: How clients authenticate at the revocation endpoint.
        code_challenge_methods_supported:
          type: array
          items: { type: string }
          description: Always `["S256"]`.
        authorization_response_iss_parameter_supported:
          type: boolean
          description: "`true`: every authorization response carries `iss` (RFC 9207)."
        client_id_metadata_document_supported:
          type: boolean
          description: "`true`: a client may use the HTTPS URL of its metadata document as its `client_id`."
        service_documentation: { type: string, format: uri, description: These docs. }
    ProtectedResourceMetadata:
      type: object
      description: OAuth protected resource metadata, as RFC 9728 defines it.
      required: [resource, authorization_servers, scopes_supported, bearer_methods_supported]
      properties:
        resource: { type: string, format: uri, description: "The MCP server's URL." }
        resource_name: { type: string, description: The name MCP clients show. }
        authorization_servers:
          type: array
          items: { type: string, format: uri }
          description: "The issuers whose tokens the server accepts: `https://app.reflections.ai`."
        scopes_supported:
          type: array
          items: { $ref: "#/components/schemas/OAuthScope" }
          description: The scopes the MCP server's tools need.
        bearer_methods_supported:
          type: array
          items: { type: string }
          description: "Always `[\"header\"]`: send the token in the `Authorization` header."
        resource_documentation: { type: string, format: uri, description: The MCP server's documentation. }
    ReceiptLicense:
      type: object
      required: [talent, license, license_revision, terms_digest]
      properties:
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent whose license applied. }
        license: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: The license the decision relied on. }
        license_revision:
          type: string
          pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The signed revision of that license the decision relied on. The JWS claim names it
            `revision`.
        terms_digest:
          $ref: "#/components/schemas/Digest"
          description: |
            The `terms_digest` of that revision. Compare it with the revision's own to confirm which
            terms applied.
    VerificationCreate:
      type: object
      description: Send exactly one of `receipt`, `manifest`, `url`, `sha256` or `fingerprint`.
      properties:
        receipt: { type: string, description: "A receipt ID or JWS." }
        manifest: { type: string, contentEncoding: base64, description: "A C2PA manifest store." }
        url: { type: string, format: uri, description: "A file Reflections can fetch." }
        sha256:
          $ref: "#/components/schemas/Sha256Hex"
          description: |
            SHA-256 of the file's bytes, in hex. Matches only an exact copy of a registered output.
        fingerprint:
          $ref: "#/components/schemas/Fingerprint"
          description: A fingerprint you computed, when the bytes cannot leave your platform.
    Verification:
      type: object
      required: [id, object, result, method, created_at]
      properties:
        id: { type: string, pattern: "^vrf_[0-9a-hjkmnp-tv-z]{26}$", description: "Unique identifier, prefixed `vrf_`." }
        object: { type: string, const: verification, description: Always `verification`. }
        result:
          type: string
          enum: [verified, not_found, invalid]
          description: "`verified`: a valid receipt matches. `not_found`: nothing matches; this says nothing about whether the content is licensed. `invalid`: a receipt or manifest is present and fails verification."
        method:
          type: string
          enum: [receipt, manifest, digest, fingerprint, watermark]
          description: |
            How the content matched: its `receipt`, an embedded `manifest`, the exact `digest`, a
            `fingerprint` or a `watermark`.
        match:
          type: [object, "null"]
          description: How the file matched a registered output, for `digest`, `fingerprint` and `watermark`. `null` when a receipt or manifest matched.
          properties:
            exact: { type: boolean, description: "The bytes match the registered digest." }
            confidence:
              type: string
              enum: [exact, high, medium]
              description: |
                How close the match is: `exact` for the registered bytes, `high` or `medium` for a
                fingerprint. Treat `medium` as weaker evidence.
        manifest:
          type: [object, "null"]
          description: |
            The C2PA manifest read from the file or sent as `manifest`. `null` when none was read.
          properties:
            signer: { type: string, description: "The C2PA claim signer." }
            assertion_present:
              type: boolean
              description: Whether the manifest carries the `ai.reflections.license` assertion.
            signature_valid:
              type: boolean
              description: |
                Whether the C2PA claim signature verifies. The receipt inside is checked separately,
                against Reflections' keys.
        receipt:
          description: |
            The matching receipt, in full, with its live `use_status`. `null` when nothing matched.
          oneOf:
            - $ref: "#/components/schemas/Receipt"
            - type: "null"
        detail: { type: [string, "null"], description: "What failed, when `result` is `invalid`. Otherwise `null`." }
        created_at: { type: string, format: date-time, description: When the verification was made. }

    # ---------- Revocations ----------
    RevocationStatus:
      type: string
      description: |
        `pending_acknowledgement`: some required action is not yet acknowledged. `acknowledged`:
        every required action is. `overdue`: a deadline passed first, `acknowledge_by` or
        `post_revocation.withdraw_by`.
      enum: [pending_acknowledgement, acknowledged, overdue]
    RevocationAction:
      type: string
      description: |
        `stop_generation`: issue nothing new under the targets. `purge_cached_decisions`: drop
        cached checks and authorizations. `delete_provider_copies`: delete copies held at model
        providers, such as voices. `cease_distribution`: place released outputs nowhere new.
        `withdraw_outputs`: take released outputs down.
      enum: [stop_generation, purge_cached_decisions, delete_provider_copies, cease_distribution, withdraw_outputs]
    Revocation:
      type: object
      required: [id, object, livemode, scope, targets, status, initiated_by, effective_at, required_actions, acknowledge_by, acknowledgements, created_at]
      properties:
        id:
          type: string
          pattern: "^rvk_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The revocation's ID. Pass it as `after` to read the revocations created after it.
        object: { type: string, const: revocation, description: Always `revocation`. }
        livemode:
          type: boolean
          description: "`true` in live mode, `false` for an object created with a test key."
        scope:
          type: string
          enum: [license, facet, mandate, talent]
          description: "`license`: one license. `facet`: a facet withdrawn, which narrows every license that covers it. `mandate`: a representative's authority ended. `talent`: consent withdrawn everywhere."
        targets:
          type: object
          description: What the revocation cuts. Which fields are set depends on `scope`.
          properties:
            talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent whose consent narrowed. Set at every scope. }
            licenses:
              type: array
              items: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$" }
              description: |
                The licenses cut: the revoked license, every license that covers a withdrawn facet,
                or the licenses the talent revoked with an ended mandate.
            facets:
              type: array
              items: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$" }
              description: |
                The withdrawn facets, for `scope` `facet`. Other scopes may list facets of the cut
                licenses that need action, such as one with a copy in `provider_copies`.
            mandate:
              type: [string, "null"]
              pattern: "^mnd_[0-9a-hjkmnp-tv-z]{26}$"
              description: The ended mandate, for `scope` `mandate`. Null at other scopes.
        status:
          $ref: "#/components/schemas/RevocationStatus"
          description: |
            `pending_acknowledgement` until every required action is acknowledged, then
            `acknowledged`, or `overdue` if a deadline passes first.
        initiated_by:
          type: string
          enum: [talent, representative, reflections]
          description: |
            Who revoked: the talent in the Talent Portal, a representative whose mandate has
            `revoke`, or Reflections.
        for_cause: { type: boolean, description: "Revoked for a breach. Only then can `withdraw` apply." }
        cause: { type: [string, "null"], description: "For a revocation for cause, the breach, as whoever revoked it stated it." }
        note: { type: [string, "null"], description: "A note from whoever revoked it." }
        effective_at:
          type: string
          format: date-time
          description: When the revocation took effect. `acknowledge_by` is 24 hours later.
        post_revocation:
          type: object
          description: |
            What happens to outputs released before `effective_at`, copied from the license's
            `post_revocation` term.
          properties:
            policy:
              type: string
              enum: [retain, cease_distribution, withdraw]
              description: |
                `retain`: released outputs stay usable within their scope and window.
                `cease_distribution`: no new placements. `withdraw`: take them down by
                `withdraw_by`; only when `for_cause` is `true`.
            withdraw_by:
              type: [string, "null"]
              format: date-time
              description: |
                When released outputs must be down and `withdraw_outputs` acknowledged. Null unless
                `policy` is `withdraw`.
        required_actions:
          type: array
          items: { $ref: "#/components/schemas/RevocationAction" }
          description: What every platform that used the targets must do and acknowledge.
        provider_copies:
          type: array
          description: Copies at model providers you must delete.
          items:
            type: object
            properties:
              facet: { type: string, pattern: "^fct_[0-9a-hjkmnp-tv-z]{26}$", description: The facet the copy was made from. }
              provider: { type: string, description: The model provider that holds the copy. }
              external_id:
                type: string
                description: |
                  The copy's ID at the provider, such as a voice ID. Delete the copy by this ID.
        affected:
          type: object
          description: What the revocation cut, at `effective_at`.
          properties:
            checks_denied:
              type: integer
              description: |
                Checks pending or escalated at `effective_at`, now denied with `license_revoked`.
            generations_denied: { type: integer, description: "Held outputs that can no longer be released." }
            sessions_terminated: { type: integer, description: "Live sessions ended, each with `session.terminated`." }
            released_outputs: { type: integer, description: "Released outputs now governed by `post_revocation`." }
        acknowledge_by:
          type: string
          format: date-time
          description: |
            When every required action except `withdraw_outputs` must be acknowledged: 24 hours
            after `effective_at`.
        acknowledgements:
          type: array
          items:
            type: object
            required: [account, actions, acknowledged_at]
            properties:
              account: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The platform that acknowledged. }
              actions:
                type: array
                items: { $ref: "#/components/schemas/RevocationAction" }
                description: The actions this acknowledgement attests were done.
              deleted_copies:
                type: array
                items:
                  type: object
                  properties:
                    provider: { type: string, description: The model provider that held the copy. }
                    external_id:
                      type: string
                      description: The copy's ID at the provider, from `provider_copies`.
                    deleted_at: { type: string, format: date-time, description: When the platform deleted the copy. }
                description: The provider copies the platform deleted.
              note: { type: [string, "null"], description: "The platform's note, as sent." }
              acknowledged_at: { type: string, format: date-time, description: When Reflections received the acknowledgement. }
          description: |
            Each acknowledgement a platform sent, in the order received. Shown on the talent's
            record.
        created_at: { type: string, format: date-time, description: When Reflections recorded the revocation. }
    RevocationList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Revocation" }
              description: Revocations, newest first, or oldest first when you pass `after`.
    AcknowledgementCreate:
      type: object
      required: [actions]
      properties:
        actions:
          type: array
          description: |
            The actions you completed. By `acknowledge_by`, acknowledge every required action
            except `withdraw_outputs`. Acknowledge `withdraw_outputs` in a later call, by
            `post_revocation.withdraw_by`. Each call adds to the revocation's `acknowledgements`.
          items: { $ref: "#/components/schemas/RevocationAction" }
        deleted_copies:
          type: array
          items:
            type: object
            required: [provider, external_id, deleted_at]
            properties:
              provider: { type: string, description: "The provider, as in `provider_copies`." }
              external_id:
                type: string
                description: The copy's ID at the provider, as in `provider_copies`.
              deleted_at: { type: string, format: date-time, description: When you deleted the copy. }
          description: |
            Each copy from `provider_copies` you deleted. List every one when you acknowledge
            `delete_provider_copies`.
        note: { type: string, maxLength: 1000, description: Shown with your acknowledgement on the talent's record. }

    # ---------- Usage and statements ----------
    UsageUnits:
      type: string
      enum: [outputs, seconds, characters, placements, impressions]
    UsageRecordCreate:
      type: object
      required: [subject, units, quantity, occurred_at]
      properties:
        subject:
          type: string
          pattern: "^(gen|ses)_[0-9a-hjkmnp-tv-z]{26}$"
          description: The generation or session this record settles.
        license:
          type: string
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: The license the usage counts against. Required when the subject was decided under more than one license; send one record per license.
        units:
          $ref: "#/components/schemas/UsageUnits"
          description: |
            The unit `quantity` counts. Report the `units` the `usage_report` obligation names.
        quantity: { type: number, minimum: 0, description: "How many `units`. May be fractional, such as `3.4` seconds." }
        occurred_at: { type: string, format: date-time, description: When the use happened. }
        placement:
          type: object
          description: For `placements` and `impressions`.
          properties:
            channel: { $ref: "#/components/schemas/Channel", description: Where the output was placed. }
            territory: { $ref: "#/components/schemas/Territory", description: The country where the output was placed or shown. }
            url: { type: string, format: uri, description: "The placement's address, when it has one." }
        correction_of: { type: string, pattern: "^ur_[0-9a-hjkmnp-tv-z]{26}$", description: The record this one replaces. }
        metadata:
          $ref: "#/components/schemas/Metadata"
          description: Your own keys, such as your batch ID. Returned on the record.
    UsageRecordBatchCreate:
      type: object
      required: [records]
      properties:
        records:
          type: array
          minItems: 1
          maxItems: 1000
          items: { $ref: "#/components/schemas/UsageRecordCreate" }
          description: 1 to 1,000 records. Each is accepted or rejected on its own.
    UsageRecord:
      allOf:
        - $ref: "#/components/schemas/UsageRecordCreate"
        - type: object
          required: [id, object, livemode, status, license, created_at]
          properties:
            id:
              type: string
              pattern: "^ur_[0-9a-hjkmnp-tv-z]{26}$"
              description: The record's ID. Name it in `correction_of` to replace the record.
            object: { type: string, const: usage_record, description: Always `usage_record`. }
            livemode:
              type: boolean
              description: "`true` in live mode, `false` for an object created with a test key."
            status:
              type: string
              enum: [accepted, rejected]
              description: |
                `accepted`: counted in reconciliation. `rejected`: not counted; `rejection` says
                why.
            rejection:
              type: [object, "null"]
              description: Why the record was rejected. Null when `accepted`.
              properties:
                code:
                  type: string
                  enum: [unknown_subject, exceeds_observed, outside_scope, duplicate, period_closed]
                  description: |
                    `unknown_subject`: no such generation or session under your licenses.
                    `exceeds_observed`: more units than Reflections recorded. `outside_scope`: the
                    placement is outside the license's channels or territories. `duplicate`: this
                    subject, license and unit are already reported. `period_closed`: the statement
                    for that period was already issued.
                detail: { type: string, description: "What was wrong, in words." }
            license:
              type: [string, "null"]
              pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
              description: |
                The license the record counts against, as you sent it or as Reflections found it.
                Null when no license was found for `subject`.
            statement:
              type: [string, "null"]
              pattern: "^stmt_[0-9a-hjkmnp-tv-z]{26}$"
              description: The statement the record counts in. Null when `rejected`.
            created_at: { type: string, format: date-time, description: When Reflections received the record. }
    UsageRecordList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/UsageRecord" }
              description: |
                Usage records. Report usage returns them in the order you sent; List usage records
                returns them newest first.
    StatementStatus:
      type: string
      description: "`open`: the month is still running. `issued`: final for the month. `paid`: the talent's side confirmed payment. `disputed`: the talent's side disputed it."
      enum: [open, issued, paid, disputed]
    Statement:
      type: object
      required: [id, object, livemode, license, talent, licensee, status, period, currency, lines, amount_due, amount_paid, reconciliation, created_at]
      properties:
        id:
          type: string
          pattern: "^stmt_[0-9a-hjkmnp-tv-z]{26}$"
          description: The statement's ID. Record, confirm and dispute payments against it.
        object: { type: string, const: statement, description: Always `statement`. }
        livemode:
          type: boolean
          description: |
            `true` in live mode, `false` in test mode, where statements are generated daily.
        license:
          type: string
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The license the statement covers. Each statement covers one license for one month.
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent the licensee owes. }
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: The account that holds the license and pays the talent's payee.
        status:
          $ref: "#/components/schemas/StatementStatus"
          description: |
            `open` while the month runs, then `issued`. `paid` once confirmed payments reach
            `amount_due`, or `disputed` while the talent's side disputes it.
        period:
          type: object
          description: The month the statement covers.
          properties:
            start: { type: string, format: date-time, description: "The start of the period, inclusive." }
            end:
              type: string
              format: date-time
              description: "The end of the period, exclusive: the start of the next month."
        currency:
          type: string
          pattern: "^[a-z]{3}$"
          description: The ISO 4217 code, lowercase, of every amount on the statement.
        lines:
          type: array
          items:
            type: object
            properties:
              description: { type: string, description: "The line's label, as the statement document shows it." }
              units: { $ref: "#/components/schemas/UsageUnits", description: "The unit counted, from the license's `compensation`." }
              reported: { type: number, description: "Units you reported." }
              observed: { type: number, description: "Units Reflections recorded from checks and generations." }
              billable: { type: number, description: "The greater of reported and observed." }
              rate:
                description: |
                  The license's rate for this unit. Null for a line without a per-unit rate.
                oneOf:
                  - $ref: "#/components/schemas/Money"
                  - type: "null"
              amount: { type: integer, description: "`billable` at `rate`, in the currency's smallest unit." }
          description: One line per unit the license bills.
        amount_due:
          type: integer
          description: |
            What the licensee owes for the period under the license's `compensation`, in the
            currency's smallest unit.
        amount_paid: { type: integer, description: "The total of `payments`, in the currency's smallest unit." }
        reconciliation:
          type: object
          description: How the units reported compare with the units Reflections observed.
          properties:
            result:
              type: string
              enum: [matched, under_reported, over_reported]
              description: |
                `matched`: reported and observed agree. `under_reported`: Reflections observed more
                than was reported. `over_reported`: more was reported than observed.
            detail: { type: [string, "null"], description: "The difference, in words. Null when `matched`." }
        payments:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                pattern: "^pay_[0-9a-hjkmnp-tv-z]{26}$"
                description: The payment's ID. The talent's side passes it to Confirm a payment.
              amount: { type: integer, description: In the currency's smallest unit. }
              paid_at: { type: string, format: date-time, description: When the licensee says it paid. }
              method: { type: string, enum: [bank_transfer, card, check, other], description: How the licensee says it paid. }
              reference:
                type: [string, "null"]
                description: |
                  The licensee's payment reference, such as a wire ID. Null if it gave none.
              confirmed_at: { type: [string, "null"], format: date-time, description: "When the talent's side confirmed receipt." }
          description: Payments the licensee recorded against the statement, in the order recorded.
        dispute:
          type: [object, "null"]
          description: Present while the talent's side disputes the statement.
          properties:
            reason:
              type: string
              description: Why the talent's side disputes the statement, as written.
            disputed_at: { type: string, format: date-time, description: When the talent's side disputed the statement. }
        due_at: { type: [string, "null"], format: date-time, description: When payment is due. Null while `open`. }
        issued_at:
          type: [string, "null"]
          format: date-time
          description: |
            When the statement was issued, or last reissued after a dispute. Null while `open`.
        document_url:
          type: [string, "null"]
          format: uri
          description: The statement as a document a person reads. Null while `open`.
        created_at: { type: string, format: date-time, description: "When the statement opened, at the start of its period." }
    StatementList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Statement" }
              description: Statements, newest first.
    PaymentCreate:
      type: object
      required: [amount, currency, paid_at, method]
      properties:
        amount: { type: integer, minimum: 1, description: "What you paid, in the currency's smallest unit." }
        currency:
          type: string
          pattern: "^[a-z]{3}$"
          description: The ISO 4217 code, lowercase, as in the statement's `currency`.
        paid_at: { type: string, format: date-time, description: When you paid the talent's payee. }
        method: { type: string, enum: [bank_transfer, card, check, other], description: How you paid the talent's payee. }
        reference: { type: string, maxLength: 200, description: "Your payment reference, such as a wire ID." }

    # ---------- Talent side ----------
    Mandate:
      type: object
      description: A talent's appointment of your account as their representative, with the powers they chose.
      required: [id, object, livemode, talent, talent_name, representative, role, powers, status, starts_at, created_at]
      properties:
        id: { type: string, pattern: "^mnd_[0-9a-hjkmnp-tv-z]{26}$", description: "The mandate's ID, `mnd_…`." }
        object: { type: string, const: mandate, description: Always `mandate`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent who appointed you. }
        talent_name: { type: string, description: "The talent's name, for display." }
        representative: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: Your account. }
        role:
          type: string
          enum: [agency, manager, estate, union, legal]
          description: |
            The kind of representative the talent appointed you as. `legal` is legal counsel.
        powers:
          type: array
          description: |
            `issue_licenses`: draft licenses and answer license requests. `review_outputs`: resolve
            escalations and release held outputs. `revoke`: suspend, resume and revoke licenses.
            `receive_statements`: read statements, confirm payments and dispute statements.
          items: { type: string, enum: [issue_licenses, review_outputs, revoke, receive_statements] }
        status:
          type: string
          enum: [active, ended]
          description: |
            `active` while you may act for the talent. `ended` once the talent ended it or `ends_at`
            passed.
        starts_at: { type: string, format: date-time, description: When you may start acting for the talent. }
        ends_at: { type: [string, "null"], format: date-time, description: "When the mandate ends on its own, if the talent set an end." }
        ended_at: { type: [string, "null"], format: date-time, description: When the mandate ended. `null` while `active`. }
        revocation:
          type: [string, "null"]
          pattern: "^rvk_[0-9a-hjkmnp-tv-z]{26}$"
          description: The revocation with `scope` `mandate` that ended it, when the talent ended it.
        created_at: { type: string, format: date-time, description: When the talent appointed you in the Talent Portal. }
    MandateList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/Mandate" }
              description: The mandates on this page.
    EscalationDetail:
      title: Escalation
      description: An escalation with the request, use and findings a reviewer needs.
      allOf:
        - $ref: "#/components/schemas/Escalation"
        - type: object
          required: [object, livemode, subject, talent, license, licensee, platform, use, request_digest, created_at]
          properties:
            object: { type: string, const: escalation, description: Always `escalation`. }
            livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
            subject:
              type: object
              description: What waits on the decision.
              required: [object, id]
              properties:
                object:
                  type: string
                  enum: [check, generation]
                  description: "`check` for an escalated check, `generation` for a held output."
                id: { type: string, description: "The check (`chk_…`) or generation (`gen_…`) ID." }
            talent:
              type: string
              pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$"
              description: |
                The talent whose side decides. When a check escalates for several talent, each has
                their own escalation.
            license: { type: string, pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$", description: The license the request was checked under. }
            license_revision:
              type: string
              pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$"
              description: The revision of `license` the request was checked against.
            licensee: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The account that holds `license`. }
            licensee_name: { type: string, description: The licensee's account name. }
            platform: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The platform that ran the check or submitted the output. }
            platform_name: { type: string, description: The platform's account name. }
            use: { $ref: "#/components/schemas/Use", description: The use the platform asked for on the check. }
            inputs:
              type: array
              description: |
                The request as the platform sent it. Media inputs carry a `url` that opens for 15
                minutes. Text sent withheld appears as `role` and `sha256` only.
              items: { $ref: "#/components/schemas/Input" }
            reasons:
              type: array
              description: What raised the question, with the talent's term.
              items: { $ref: "#/components/schemas/Reason" }
            findings:
              type: array
              description: For a held output, what Reflections recorded on its bytes.
              items: { $ref: "#/components/schemas/Finding" }
            artifact:
              type: [object, "null"]
              description: For a held output, the clean bytes to review.
              properties:
                sha256:
                  $ref: "#/components/schemas/Sha256Hex"
                  description: |
                    SHA-256 of the held output's bytes, as on the generation's `artifact`.
                media_type: { type: string, description: "The output's media type, such as `image/png`." }
                url: { type: string, format: uri, description: Opens for 15 minutes. }
            request_digest:
              $ref: "#/components/schemas/Digest"
              description: |
                The `request_digest` of the check. Allowing an escalated check covers exactly this
                request.
            review_url:
              type: [string, "null"]
              format: uri
              description: The Talent Portal page where a person with authority reviews it and decides. Present while `open`.
            decision:
              type: [string, "null"]
              enum: [allow, deny, null]
              description: |
                The decision a person recorded, `allow` or `deny`. `null` until one is recorded.
            decided_by:
              type: [object, "null"]
              description: Who resolved it.
              properties:
                party:
                  type: string
                  enum: [talent, representative, reflections]
                  description: |
                    `talent` when the talent decided, `representative` when a representative
                    recorded the decision, `reflections` for an escalation under a platform license.
                account:
                  type: [string, "null"]
                  pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
                  description: |
                    The representative's account. `null` when the talent or Reflections decided.
                name:
                  type: string
                  description: The person who decided, as recorded on the talent's audit record.
            created_at: { type: string, format: date-time, description: When the check escalated or the output was held. }
    EscalationList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/EscalationDetail" }
              description: The escalations on this page.
    EscalationResolve:
      type: object
      required: [decision, decided_by]
      properties:
        decision:
          type: string
          enum: [allow, deny]
          description: For a held output, `allow` releases it and `deny` declines it.
        note: { type: string, maxLength: 500, description: "Shown to the platform as `escalation.note`." }
        decided_by:
          type: object
          description: The person who made the decision. Recorded on the talent's audit record.
          required: [name]
          properties:
            name:
              type: string
              maxLength: 200
              description: |
                The full name of the person who decided, as it appears on the talent's audit record.
    LicenseDraftStatus:
      type: string
      description: |
        `open`: waiting for a signature at `signing_url`. `signed`: signed; `license` and
        `license_revision` name the result. `declined`: the signer declined it. `discarded`: you
        discarded it, or the mandate ended. `expired`: not signed by `expires_at`.
      enum: [open, signed, declined, discarded, expired]
    LicenseDraftCreate:
      type: object
      required: [talent]
      properties:
        talent:
          type: string
          pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The talent the license is for. Your mandate for them must include `issue_licenses`.
        kind:
          type: string
          enum: [issue, change_request, amend, renew]
          default: issue
          description: |
            `issue`: a new license, with `licensee` and a full `scope`. `change_request`: an answer
            to a request of kind `change`; set by `license_request`. `amend`: new terms for an
            active or scheduled `license`. `renew`: a new window for an active, scheduled or expired
            `license`. Set `license_request` and the kind follows from the request.
        license_request:
          type: string
          pattern: "^lrq_[0-9a-hjkmnp-tv-z]{26}$"
          description: The request this draft answers. The request must be `sent`. When the draft is signed, the request becomes `signed`.
        license:
          type: string
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: For `amend` and `renew`, the license to change.
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: For `issue` without a `license_request`, the account that will hold the license. It must have `hold_licenses`.
        scope:
          $ref: "#/components/schemas/LicenseScope"
          description: |
            The terms. For `issue` without a `license_request`, the full scope. With a
            `license_request`, only the terms that differ from what was asked. For `amend` and
            `renew`, only the terms that change; omitted fields keep the current revision's value.
        signer:
          type: string
          enum: [talent, representative]
          default: talent
          description: |
            Who signs. `talent`: the talent signs in the Talent Portal and is notified now.
            `representative`: a person at your account with `issue_licenses` signs.
        note:
          type: string
          maxLength: 1000
          description: Shown to the licensee on the acceptance page.
        expires_at:
          type: string
          format: date-time
          description: When the draft can no longer be signed. At most 30 days ahead, and the default.
        metadata: { $ref: "#/components/schemas/Metadata", description: "Keys and values of your own, returned on the draft." }
    LicenseDraftUpdate:
      type: object
      properties:
        scope:
          $ref: "#/components/schemas/LicenseScope"
          description: |
            The terms to change. Fields you send replace the draft's; fields you omit keep their
            value.
        signer:
          type: string
          enum: [talent, representative]
          description: |
            Who signs: `talent`, or `representative` for a person at your account with
            `issue_licenses`.
        note:
          type: string
          maxLength: 1000
          description: Replaces the note shown to the licensee on the acceptance page.
        expires_at:
          type: string
          format: date-time
          description: |
            A new time after which the draft can no longer be signed. At most 30 days ahead.
        metadata: { $ref: "#/components/schemas/Metadata", description: Replaces the draft's `metadata`. }
    LicenseDraft:
      type: object
      required: [id, object, livemode, status, kind, talent, licensee, scope, terms_digest, signer, created_by, expires_at, created_at]
      properties:
        id: { type: string, pattern: "^ldr_[0-9a-hjkmnp-tv-z]{26}$", description: "The draft's ID, `ldr_…`." }
        object: { type: string, const: license_draft, description: Always `license_draft`. }
        livemode: { type: boolean, description: "`true` in live mode, `false` in test mode." }
        status:
          $ref: "#/components/schemas/LicenseDraftStatus"
          description: |
            `open` until the signer signs or declines it, it is discarded, or it passes
            `expires_at`.
        kind:
          type: string
          enum: [issue, change_request, amend, renew]
          description: |
            What signing creates. `issue`: a new license. `change_request`: a new revision answering
            a request of kind `change`. `amend`: new terms for `license`. `renew`: a new window for
            `license`.
        talent: { type: string, pattern: "^tal_[0-9a-hjkmnp-tv-z]{26}$", description: The talent the license is for. }
        licensee:
          type: string
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: |
            The account that holds or will hold the license. It accepts what is signed on its hosted
            acceptance page.
        license:
          type: [string, "null"]
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: The license this draft changes, or, once an `issue` draft is signed, the license it became.
        license_request:
          type: [string, "null"]
          pattern: "^lrq_[0-9a-hjkmnp-tv-z]{26}$"
          description: The license request this draft answers. `null` when it answers none.
        scope:
          $ref: "#/components/schemas/LicenseScope"
          description: The full terms the signer will see, with the current revision's values filled in.
        terms_digest:
          $ref: "#/components/schemas/Digest"
          description: |
            The `terms_digest` the revision will carry if it is signed as drafted. Compare it with
            the signed revision's to see whether the signer changed anything.
        signer:
          type: string
          enum: [talent, representative]
          description: |
            Who signs. `talent`: the talent, in the Talent Portal. `representative`: a person at
            your account with `issue_licenses`.
        signing_url:
          type: [string, "null"]
          format: uri
          description: The Talent Portal page where the signer reads and signs the draft with a passkey. Present while `open`.
        signed_as_drafted:
          type: [boolean, "null"]
          description: Once signed, `false` when the signer changed terms before signing.
        license_revision: { type: [string, "null"], pattern: "^lrv_[0-9a-hjkmnp-tv-z]{26}$", description: The revision that signing created. }
        decision_note: { type: [string, "null"], description: "The signer's note when they declined." }
        note:
          type: [string, "null"]
          description: Shown to the licensee on the acceptance page. `null` when you sent none.
        created_by: { type: string, pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$", description: The representative account that prepared the draft. }
        expires_at:
          type: string
          format: date-time
          description: |
            When the draft can no longer be signed. 30 days after it was created, unless you set an
            earlier time.
        signed_at: { type: [string, "null"], format: date-time, description: When the signer signed. `null` unless `signed`. }
        declined_at: { type: [string, "null"], format: date-time, description: When the signer declined. `null` unless `declined`. }
        metadata: { $ref: "#/components/schemas/Metadata", description: Keys and values of your own. }
        created_at: { type: string, format: date-time, description: When you created the draft. }
    LicenseDraftList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/LicenseDraft" }
              description: The drafts on this page.
    LicenseRequestDecline:
      type: object
      properties:
        decision_note: { type: string, maxLength: 1000, description: "Shown to the licensee as `decision_note`." }
    LicenseStatusChange:
      type: object
      properties:
        note: { type: string, maxLength: 1000, description: "Shown to the licensee on the license page." }
    RevocationCreate:
      type: object
      required: [license]
      properties:
        license:
          type: string
          pattern: "^lic_[0-9a-hjkmnp-tv-z]{26}$"
          description: The license to revoke. The revocation has `scope` `license` and names the license's talent in `targets.talent`.
        for_cause: { type: boolean, default: false, description: "Revoked for a breach. Only then does a license's `withdraw` policy apply." }
        cause:
          type: string
          maxLength: 1000
          description: Required when `for_cause` is `true`. Shown to the licensee and to every platform that must act, as the revocation's `cause`.
        note: { type: string, maxLength: 1000, description: "Shown to the licensee and platforms as the revocation's `note`." }
    PaymentConfirm:
      type: object
      properties:
        received_at: { type: string, format: date-time, description: "When the payment arrived. Defaults to now." }
    StatementDispute:
      type: object
      required: [reason]
      properties:
        reason: { type: string, maxLength: 2000, description: "Shown to the licensee as `dispute.reason`." }

    # ---------- Webhooks and events ----------
    EventType:
      type: string
      enum:
        - license.issued
        - license.accepted
        - license.revised
        - license.revision_pending
        - license.revision_declined
        - license.suspended
        - license.resumed
        - license.revoked
        - license.expired
        - license.declined
        - license_request.created
        - license_request.signed
        - license_request.declined
        - license_draft.signed
        - license_draft.declined
        - check.resolved
        - escalation.created
        - generation.allowed
        - generation.released
        - generation.denied
        - generation.expired
        - session.terminated
        - revocation.created
        - revocation.overdue
        - connection.created
        - connection.revoked
        - facet.updated
        - talent.updated
        - statement.issued
        - statement.disputed
        - mandate.created
        - mandate.ended
        - webhook_endpoint.disabled
    WebhookEndpointCreate:
      type: object
      required: [url, events]
      properties:
        url: { type: string, format: uri, description: "An HTTPS URL." }
        events:
          type: array
          minItems: 1
          description: Event types to send, or `["*"]` for all.
          items:
            anyOf:
              - $ref: "#/components/schemas/EventType"
              - { type: string, const: "*", description: Every event type. }
        description: { type: string, maxLength: 500, description: "Your label for the endpoint, such as `Production`." }
        api_version: { type: string, description: "The version events are rendered in. Defaults to your account's version." }
        connected: { type: boolean, default: false, description: "Also send events about connected licensees' objects." }
        metadata: { $ref: "#/components/schemas/Metadata", description: "Keys and values of your own, returned on the endpoint." }
    WebhookEndpointUpdate:
      type: object
      properties:
        url: { type: string, format: uri, description: A new HTTPS URL. }
        events:
          type: array
          minItems: 1
          items:
            anyOf:
              - $ref: "#/components/schemas/EventType"
              - { type: string, const: "*", description: Every event type. }
          description: Replaces the event types to send. `["*"]` for every type.
        description: { type: string, maxLength: 500, description: Replaces your label for the endpoint. }
        status: { type: string, enum: [enabled], description: "Re-enable a disabled endpoint." }
        metadata: { $ref: "#/components/schemas/Metadata", description: Replaces the endpoint's `metadata`. }
    WebhookEndpoint:
      type: object
      required: [id, object, livemode, url, events, status, api_version, created_at]
      properties:
        id: { type: string, pattern: "^we_[0-9a-hjkmnp-tv-z]{26}$", description: "The endpoint's ID, `we_…`." }
        object: { type: string, const: webhook_endpoint, description: Always `webhook_endpoint`. }
        livemode:
          type: boolean
          description: |
            `true` for an endpoint created with a live key, which receives only live events. `false`
            for one created with a test key, which receives only test events.
        url: { type: string, format: uri, description: The HTTPS URL events are sent to. }
        events:
          type: array
          items:
            anyOf:
              - $ref: "#/components/schemas/EventType"
              - { type: string, const: "*", description: Every event type. }
          description: |
            The event types sent to this endpoint. `["*"]` sends every type, including types added
            later.
        description: { type: [string, "null"], description: Your label for the endpoint. `null` when you set none. }
        status:
          type: string
          enum: [enabled, disabled]
          description: |
            `enabled`, or `disabled` after every delivery failed for 5 days. Re-enable a disabled
            endpoint by updating it with `status: enabled`.
        disabled_reason:
          type: [string, "null"]
          description: Why Reflections disabled the endpoint. `null` while `enabled`.
        api_version:
          type: string
          description: |
            The version events are rendered in. Set when the endpoint is created; it cannot be
            changed.
        connected:
          type: boolean
          description: |
            Whether the endpoint also receives events about connected licensees' objects. Those
            events carry the licensee's ID in `account`.
        secret:
          type: [string, "null"]
          description: "`whsec_…`. Returned only when the endpoint is created or its secret rotated."
        metadata: { $ref: "#/components/schemas/Metadata", description: Keys and values of your own. }
        created_at: { type: string, format: date-time, description: When the endpoint was created. }
    WebhookEndpointList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/WebhookEndpoint" }
              description: The endpoints on this page.
    Event:
      type: object
      required: [id, object, type, api_version, livemode, sequence, created_at, data]
      properties:
        id: { type: string, pattern: "^evt_[0-9a-hjkmnp-tv-z]{26}$", description: Equal to the `webhook-id` header. }
        object: { type: string, const: event, description: Always `event`. }
        type: { $ref: "#/components/schemas/EventType", description: "What happened, such as `check.resolved`." }
        api_version: { type: string, description: The API version `data.object` is rendered in. }
        livemode: { type: boolean, description: "`true` for live events, `false` for test events." }
        account:
          type: [string, "null"]
          pattern: "^acct_[0-9a-hjkmnp-tv-z]{26}$"
          description: The connected licensee the event concerns, when it is not your own account.
        sequence:
          type: integer
          description: Increases by one with each event about the same object. Ignore an event whose sequence is lower than one you have processed.
        created_at: { type: string, format: date-time, description: When the event happened. }
        data:
          type: object
          description: The object the event is about and, for a change, the fields that changed.
          required: [object]
          properties:
            object: { type: object, description: "The object as it was when the event happened." }
            previous_attributes:
              type: object
              description: The fields that changed, with their old values.
    AnyEvent:
      description: An event of any type. `type` names it, and `data.object` is the object that type carries.
      oneOf:
        - { $ref: "#/components/schemas/LicenseEvent" }
        - { $ref: "#/components/schemas/LicenseRequestEvent" }
        - { $ref: "#/components/schemas/CheckEvent" }
        - { $ref: "#/components/schemas/GenerationEvent" }
        - { $ref: "#/components/schemas/SessionEvent" }
        - { $ref: "#/components/schemas/RevocationEvent" }
        - { $ref: "#/components/schemas/ConnectionEvent" }
        - { $ref: "#/components/schemas/FacetEvent" }
        - { $ref: "#/components/schemas/TalentEvent" }
        - { $ref: "#/components/schemas/StatementEvent" }
        - { $ref: "#/components/schemas/WebhookEndpointEvent" }
        - { $ref: "#/components/schemas/LicenseDraftEvent" }
        - { $ref: "#/components/schemas/EscalationEvent" }
        - { $ref: "#/components/schemas/MandateEvent" }
      discriminator:
        propertyName: type
        mapping:
          license.issued: "#/components/schemas/LicenseEvent"
          license.accepted: "#/components/schemas/LicenseEvent"
          license.revised: "#/components/schemas/LicenseEvent"
          license.revision_pending: "#/components/schemas/LicenseEvent"
          license.revision_declined: "#/components/schemas/LicenseEvent"
          license.suspended: "#/components/schemas/LicenseEvent"
          license.resumed: "#/components/schemas/LicenseEvent"
          license.revoked: "#/components/schemas/LicenseEvent"
          license.expired: "#/components/schemas/LicenseEvent"
          license.declined: "#/components/schemas/LicenseEvent"
          license_request.signed: "#/components/schemas/LicenseRequestEvent"
          license_request.declined: "#/components/schemas/LicenseRequestEvent"
          check.resolved: "#/components/schemas/CheckEvent"
          generation.allowed: "#/components/schemas/GenerationEvent"
          generation.released: "#/components/schemas/GenerationEvent"
          generation.denied: "#/components/schemas/GenerationEvent"
          generation.expired: "#/components/schemas/GenerationEvent"
          session.terminated: "#/components/schemas/SessionEvent"
          revocation.created: "#/components/schemas/RevocationEvent"
          revocation.overdue: "#/components/schemas/RevocationEvent"
          connection.created: "#/components/schemas/ConnectionEvent"
          connection.revoked: "#/components/schemas/ConnectionEvent"
          facet.updated: "#/components/schemas/FacetEvent"
          talent.updated: "#/components/schemas/TalentEvent"
          statement.issued: "#/components/schemas/StatementEvent"
          webhook_endpoint.disabled: "#/components/schemas/WebhookEndpointEvent"
          license_request.created: "#/components/schemas/LicenseRequestEvent"
          license_draft.signed: "#/components/schemas/LicenseDraftEvent"
          license_draft.declined: "#/components/schemas/LicenseDraftEvent"
          escalation.created: "#/components/schemas/EscalationEvent"
          mandate.created: "#/components/schemas/MandateEvent"
          mandate.ended: "#/components/schemas/MandateEvent"
          statement.disputed: "#/components/schemas/StatementEvent"
    EventList:
      allOf:
        - $ref: "#/components/schemas/ListBase"
        - type: object
          properties:
            data:
              type: array
              items: { $ref: "#/components/schemas/AnyEvent" }
              description: |
                The events on this page: newest first, or oldest first when you pass `after`.

    # ---------- Event envelopes ----------
    LicenseEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [license.issued, license.accepted, license.revised, license.revision_pending, license.revision_declined, license.suspended, license.resumed, license.revoked, license.expired, license.declined], description: "The event type, one of the `license.*` event types." }
            data:
              type: object
              description: |
                The license in `object` and, when the event changed it, the old values of the
                changed fields in `previous_attributes`.
              properties:
                object: { $ref: "#/components/schemas/License", description: The license as it was when the event happened. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    LicenseRequestEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type:
              type: string
              enum: [license_request.created, license_request.signed, license_request.declined]
              description: The event type, one of the `license_request.*` event types.
            data:
              type: object
              description: |
                The license request in `object` and, when the event changed it, the old values of
                the changed fields in `previous_attributes`.
              properties:
                object:
                  $ref: "#/components/schemas/LicenseRequest"
                  description: The license request as it was when the event happened.
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    CheckEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [check.resolved], description: Always `check.resolved`. }
            data:
              type: object
              description: |
                The check in `object`, and the fields that changed in `previous_attributes`.
              properties:
                object:
                  $ref: "#/components/schemas/Check"
                  description: The check after its escalation was decided or expired.
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    GenerationEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type:
              type: string
              enum: [generation.allowed, generation.released, generation.denied, generation.expired]
              description: |
                `generation.allowed`, `generation.released`, `generation.denied` or
                `generation.expired`.
            data:
              type: object
              description: |
                The generation in `object`, and the fields that changed in `previous_attributes`.
              properties:
                object: { $ref: "#/components/schemas/Generation", description: The generation with its new `status` and `decision`. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    SessionEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [session.terminated], description: Always `session.terminated`. }
            data:
              type: object
              description: |
                The session in `object`, and the fields that changed in `previous_attributes`.
              properties:
                object:
                  $ref: "#/components/schemas/Session"
                  description: The terminated session. `termination` says why and when.
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    RevocationEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type:
              type: string
              enum: [revocation.created, revocation.overdue]
              description: |
                `revocation.created`: consent narrowed. `revocation.overdue`: a deadline passed
                before the actions due by it were acknowledged.
            data:
              type: object
              description: The revocation the event is about.
              properties:
                object: { $ref: "#/components/schemas/Revocation", description: The revocation as it was when the event happened. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    ConnectionEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type:
              type: string
              enum: [connection.created, connection.revoked]
              description: The event type, `connection.created` or `connection.revoked`.
            data:
              type: object
              description: |
                The connection in `object` and, when the event changed it, the old values of the
                changed fields in `previous_attributes`.
              properties:
                object: { $ref: "#/components/schemas/Connection", description: The connection as it was when the event happened. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    FacetEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [facet.updated], description: Always `facet.updated`. }
            data:
              type: object
              description: The facet, and in `previous_attributes` the fields that changed.
              properties:
                object: { $ref: "#/components/schemas/Facet", description: The facet as it was when the event happened. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    TalentEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [talent.updated], description: Always `talent.updated`. }
            data:
              type: object
              description: The talent, and in `previous_attributes` the fields that changed.
              properties:
                object: { $ref: "#/components/schemas/Talent", description: The talent as it was when the event happened. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    StatementEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type:
              type: string
              enum: [statement.issued, statement.disputed]
              description: |
                `statement.issued`: a statement is final for its month, or was reissued.
                `statement.disputed`: the talent's side disputed it.
            data:
              type: object
              description: The statement the event is about.
              properties:
                object: { $ref: "#/components/schemas/Statement", description: The statement as it was when the event happened. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    LicenseDraftEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [license_draft.signed, license_draft.declined], description: "`license_draft.signed` or `license_draft.declined`." }
            data:
              type: object
              description: The draft, and the fields that changed.
              properties:
                object: { $ref: "#/components/schemas/LicenseDraft", description: The draft after it was signed or declined. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    EscalationEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [escalation.created], description: Always `escalation.created`. }
            data:
              type: object
              description: The new escalation.
              properties:
                object:
                  $ref: "#/components/schemas/EscalationDetail"
                  description: |
                    The escalation as it opened, with the request, use and findings a reviewer
                    needs.
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    MandateEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [mandate.created, mandate.ended], description: "`mandate.created` or `mandate.ended`." }
            data:
              type: object
              description: The mandate and, for `mandate.ended`, the fields that changed.
              properties:
                object: { $ref: "#/components/schemas/Mandate", description: The mandate when it was created or ended. }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }
    WebhookEndpointEvent:
      allOf:
        - $ref: "#/components/schemas/Event"
        - type: object
          properties:
            type: { type: string, enum: [webhook_endpoint.disabled], description: Always `webhook_endpoint.disabled`. }
            data:
              type: object
              description: The endpoint, and the fields that changed.
              properties:
                object: { $ref: "#/components/schemas/WebhookEndpoint", description: "The endpoint, now `disabled`." }
                previous_attributes: { type: object, description: "The fields that changed, with their old values. Present on events that change the object." }

  examples:
    CheckAllow:
      summary: Allowed, with obligations
      value:
        id: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
        object: check
        livemode: true
        status: allowed
        decision: allow
        talent:
          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            name: Maya Okafor
            matched_by: name
            confidence: high
            decision: allow
            facets: [fct_5zba2q8v1m3n7p4r6s9t0wxyhk]
            license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
            license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
            terms_digest: "sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431"
        use:
          modality: image
          kind: depiction
          purpose: advertising
          commercial: true
          channels: [social, web]
          territories: [US, CA]
        reasons: []
        obligations:
          - type: generation_check
            required: all
          - type: hold_until_release
            reviewer: talent
          - type: draft_watermark
          - type: generation_instructions
            instructions:
              - "Keep Maya Okafor the same person: face, skin tone and build unchanged."
              - Do not show alcohol or tobacco.
              - Do not imply she endorses any product other than the one shown.
            term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
          - type: disclosure
            level: brand
            placement: both
            text: "Made with AI. Maya Okafor's likeness used under license by Ridgeline."
          - type: c2pa_manifest
          - type: no_training
            material: outputs
          - type: usage_report
            units: placements
            within: P30D
        authorization:
          token: "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLWF1dGgrand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwOTAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoiY2hrXzNtN3A0cjZzOXQwd3h5aGs1emJhMnE4djFuIiwic3ViIjoiYWNjdF8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJkZWNpc2lvbiI6ImFsbG93IiwiZXUiOiIzZjljMWE3ZTViMmQ4ZjQwNjFjM2U5YTdiNWQyZjgwMTZlNGM5YTNiN2QxZjVlMmM4YTZiNGQwZjllM2M3YTE1IiwiZXhlY3V0aW9uIjp7Im1vZGVsIjoiaW1hZ2UtbW9kZWwtMyIsInByb3ZpZGVyIjoiZXhhbXBsZS1pbWFnZS1wcm92aWRlciJ9LCJmYWNldHMiOlsiZmN0XzV6YmEycTh2MW0zbjdwNHI2czl0MHd4eWhrIl0sImxpY2Vuc2VzIjpbeyJsaWNlbnNlIjoibGljX2s1emJhMnE4djFtM243cDRyNnM5dDB3eHloIiwicmV2aXNpb24iOiJscnZfcDRyNnM5dDB3eHloazV6YmEycTh2MW0zbjciLCJ0YWxlbnQiOiJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiLCJ0ZXJtc19kaWdlc3QiOiJzaGEyNTY6MzlmMThjOGJlZjAyYjUyMjZiOWZlYWE5MmU1MjZlZDMwYjgxYjkxNjUwZDhhMTBiNTAzMjgxYjE2OWY0NDQzMSJ9XSwibWF4X2dlbmVyYXRpb25zIjo0LCJvYmxpZ2F0aW9ucyI6WyJnZW5lcmF0aW9uX2NoZWNrIiwiaG9sZF91bnRpbF9yZWxlYXNlIiwiZHJhZnRfd2F0ZXJtYXJrIiwiZ2VuZXJhdGlvbl9pbnN0cnVjdGlvbnMiLCJkaXNjbG9zdXJlIiwiYzJwYV9tYW5pZmVzdCIsIm5vX3RyYWluaW5nIiwidXNhZ2VfcmVwb3J0Il0sInJlcXVlc3RfZGlnZXN0Ijoic2hhMjU2OmJmOTQ4MTc3NjZkNTZkOTIyMTFkMTJmNWZmNTFhM2RjMWE2ZDVjYjRiZTI4Nzc0MTdiMDgyNTFmZTM4YzM4NmEiLCJ0YWxlbnQiOlsidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIl0sInVzZSI6eyJjaGFubmVscyI6WyJzb2NpYWwiLCJ3ZWIiXSwiY29tbWVyY2lhbCI6dHJ1ZSwia2luZCI6ImRlcGljdGlvbiIsIm1vZGFsaXR5IjoiaW1hZ2UiLCJwdXJwb3NlIjoiYWR2ZXJ0aXNpbmciLCJ0ZXJyaXRvcmllcyI6WyJVUyIsIkNBIl19LCJ2ZXIiOiIxLjAifX0.sbcXipODRBifCQEGJacDUoBBDzW1YzLdbKAv-ky0fZXjfGRTx4JQd2nap26LYy7PlMRod-7rfqLFgmWE4tutdg"
          max_generations: 4
          generations_used: 0
          expires_at: "2026-10-17T18:15:00Z"
        escalation: null
        remedy: null
        request_digest: "sha256:bf94817766d56d92211d12f5ff51a3dc1a6d5cb4be2877417b08251fe38c386a"
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        session: null
        receipt: rcpt_0wxyhk5zba2q8v1m3n7p4r6s9t
        metadata: {}
        created_at: "2026-10-17T18:00:00Z"
    CheckDeny:
      summary: Denied, with a remedy
      value:
        id: chk_8v1m3n7p4r6s9t0wxyhk5zba2q
        object: check
        livemode: true
        status: denied
        decision: deny
        talent:
          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            name: Maya Okafor
            matched_by: name
            confidence: high
            decision: deny
            facets: [fct_5zba2q8v1m3n7p4r6s9t0wxyhk]
            license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
            license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
            terms_digest: "sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431"
        use:
          modality: image
          kind: depiction
          purpose: advertising
          commercial: true
          channels: [social, web, tv]
          territories: [US, CA]
        reasons:
          - code: channel_not_licensed
            stage: check
            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.channels"
            sentence: This license covers social media and the brand's own website.
        obligations: []
        authorization: null
        escalation: null
        remedy:
          type: license_change
          license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
          suggested_scope:
            channels: [social, web, tv]
        request_digest: "sha256:b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4"
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        session: null
        receipt: rcpt_5zba2q8v1m3n7p4r6s9t0wxyhk
        metadata: {}
        created_at: "2026-10-17T18:02:00Z"
    CheckEscalate:
      summary: Escalated to the talent
      value:
        id: chk_r6s9t0wxyhk5zba2q8v1m3n7p4
        object: check
        livemode: true
        status: escalated
        decision: escalate
        talent:
          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            name: Maya Okafor
            matched_by: name
            confidence: high
            decision: escalate
            facets: [fct_5zba2q8v1m3n7p4r6s9t0wxyhk]
            license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
            license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
            terms_digest: "sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431"
            escalation: esc_t0wxyhk5zba2q8v1m3n7p4r6s9
        use:
          modality: image
          kind: depiction
          purpose: advertising
          commercial: true
          channels: [social]
          territories: [US]
        reasons:
          - code: prohibited_custom_term
            stage: check
            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
            sentence: Do not show alcohol or tobacco.
        obligations: []
        authorization: null
        escalation:
          id: esc_t0wxyhk5zba2q8v1m3n7p4r6s9
          reason: judgment
          reviewer: talent
          status: open
          expires_at: "2026-10-24T18:04:00Z"
          resolved_at: null
          note: null
        remedy: null
        request_digest: "sha256:c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5"
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        session: null
        receipt: null
        metadata: {}
        created_at: "2026-10-17T18:04:00Z"
    GenerationHeld:
      summary: Held for the talent's release
      value:
        id: gen_6s9t0wxyhk5zba2q8v1m3n7p4r
        object: generation
        livemode: true
        check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
        session: null
        candidate_index: 0
        status: held
        decision: escalate
        artifact:
          file: file_2c4e6g8j0k2m4n6p8q0r2s4t6v
          sha256: 9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a
          media_type: image/png
          duration_ms: null
        execution:
          provider: example-image-provider
          model: image-model-3
          job_id: job_88213
        findings:
          - term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes"
            attribute: identity.samePerson
            result: preserved
          - term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.adjustments"
            attribute: appearance.wardrobe
            result: preserved
          - term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
            rule: Do not show alcohol or tobacco.
            result: preserved
        unchecked_terms: []
        reasons: []
        obligations:
          - type: hold_until_release
            reviewer: talent
          - type: draft_watermark
        escalation:
          id: esc_hk5zba2q8v1m3n7p4r6s9t0wxy
          reason: release_review
          reviewer: talent
          status: open
          expires_at: "2026-10-24T18:00:12Z"
          resolved_at: null
          note: null
        assurance: observed
        receipt: null
        c2pa: null
        watermark: null
        metadata: {}
        created_at: "2026-10-17T18:00:12Z"
        decided_at: null
    GenerationAllowed:
      summary: Allowed, with a receipt to embed
      value:
        id: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
        object: generation
        livemode: true
        check: chk_m3n7p4r6s9t0wxyhk5zba2q8v1
        session: null
        candidate_index: 0
        status: allowed
        decision: allow
        artifact:
          file: file_8q0r2s4t6v8w0x2y4z6a8b0c2d
          sha256: 3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d
          media_type: audio/wav
          duration_ms: 3400
        execution:
          provider: example-voice-provider
          model: tts-2
          job_id: job_90417
        findings:
          - term: "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.requiredAttributes"
            attribute: identity.samePerson
            result: preserved
          - term: "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never"
            rule: Do not discuss politics or religion.
            result: preserved
        unchecked_terms: []
        reasons: []
        obligations:
          - type: disclosure
            level: licensed
            placement: metadata
            text: "AI voice of Maya Okafor, licensed."
          - type: c2pa_manifest
          - type: usage_report
            units: seconds
            within: P1D
        escalation: null
        assurance: observed
        receipt: rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
        c2pa:
          label: ai.reflections.license
          data:
            receipt: "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg"
            verify_url: "https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy"
        watermark: null
        metadata: {}
        created_at: "2026-10-17T18:06:02Z"
        decided_at: "2026-10-17T18:06:03Z"
    GenerationDenied:
      summary: An output that broke one of the talent's rules
      value:
        id: gen_t6v8w0x2y4z6a8b0c2d4e6f8g0
        object: generation
        livemode: true
        check: chk_3m7p4r6s9t0wxyhk5zba2q8v1n
        session: null
        candidate_index: 1
        status: denied
        decision: deny
        artifact:
          file: file_3t5v7x9z1b3d5f7h9k1m3p5r7s
          sha256: 4c6e8a0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c
          media_type: image/png
          duration_ms: null
        execution:
          provider: example-image-provider
          model: image-model-3
          job_id: job_88214
        findings:
          - term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes"
            attribute: identity.samePerson
            result: preserved
          - term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
            rule: Do not show alcohol or tobacco.
            result: violated
            detail: A wine glass on the café table.
        unchecked_terms: []
        reasons:
          - code: prohibited_custom_term
            stage: generation
            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
            sentence: Do not show alcohol or tobacco.
        obligations: []
        escalation: null
        assurance: observed
        receipt: rcpt_w0x2y4z6a8b0c2d4e6f8g0h2j4
        c2pa: null
        watermark: null
        metadata: {}
        created_at: "2026-10-17T18:08:40Z"
        decided_at: "2026-10-17T18:08:41Z"
    SessionActive:
      summary: An active session
      value:
        id: ses_q8v1m3n7p4r6s9t0wxyhk5zba2
        object: session
        livemode: true
        status: active
        check: chk_n7p4r6s9t0wxyhk5zba2q8v1m3
        license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
        talent: [tal_9t0wxyhk5zba2q8v1m3n7p4r6s]
        token: "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXNlc3Npb24rand0In0.eyJhdWQiOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwiZXhwIjoxNzkyMjYwMzAwLCJpYXQiOjE3OTIyNjAwMDAsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwic3ViIjoiYWNjdF83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRscCI6eyJjaGVjayI6ImNoa19uN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtMyIsImV1IjoiM2Y5YzFhN2U1YjJkOGY0MDYxYzNlOWE3YjVkMmY4MDE2ZTRjOWEzYjdkMWY1ZTJjOGE2YjRkMGY5ZTNjN2ExNSIsImZhY2V0cyI6WyJmY3RfdjFtM243cDRyNnM5dDB3eHloazV6YmEycTgiXSwibGljZW5zZXMiOlt7ImxpY2Vuc2UiOiJsaWNfYmEycTh2MW0zbjdwNHI2czl0MHd4eWhrNXoiLCJyZXZpc2lvbiI6Imxydl83cDRyNnM5dDB3eHloazV6YmEycTh2MW0zbiIsInRhbGVudCI6InRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyIsInRlcm1zX2RpZ2VzdCI6InNoYTI1Njo4ZTBhMmM0ZTZiOGQwZjJhNGM2ZThiMGQyZjRhNmM4ZTBiMmQ0ZjZhOGMwZTJiNGQ2ZjhhMGMyZTRiNmQ4ZjBhIn1dLCJzYW1wbGluZyI6eyJhdWRpb193aW5kb3dfbWF4IjoiUFQxNVMiLCJ0cmFuc2NyaXB0IjoiZXZlcnlfdHVybiJ9LCJzZXNzaW9uIjoic2VzX3E4djFtM243cDRyNnM5dDB3eHloazV6YmEyIiwidGFsZW50IjpbInRhbF85dDB3eHloazV6YmEycTh2MW0zbjdwNHI2cyJdLCJ1c2UiOnsiY2hhbm5lbHMiOlsiaW5fYXBwIl0sImNvbW1lcmNpYWwiOmZhbHNlLCJraW5kIjoiaW1wZXJzb25hdGlvbiIsIm1vZGFsaXR5Ijoic3BlZWNoIiwicHVycG9zZSI6InBlcnNvbmFsIiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.RD_dRcXCqGHhYvg-PV3b1JIAoAX-WzVp02x6j-eSzmhYFxuZvniuJVrhJuHmzlFq_FYr6smqYXHQzb5p8DI0gA"
        expires_at: "2026-10-17T18:05:00Z"
        renew_every: PT60S
        sampling:
          audio_window_max: PT15S
          transcript: every_turn
        obligations:
          - type: disclosure
            level: licensed
            placement: visible
            text: "AI voice of Maya Okafor, licensed."
          - type: generation_instructions
            instructions:
              - Do not discuss politics or religion.
              - Do not make promises on her behalf.
            term: "license:lic_ba2q8v1m3n7p4r6s9t0wxyhk5z/terms.voiceLineGrant.never"
          - type: usage_report
            units: seconds
            within: P1D
        reasons: []
        stream_url: "wss://app.reflections.ai/v1/sessions/ses_q8v1m3n7p4r6s9t0wxyhk5zba2/stream"
        termination: null
        ended_at: null
        metadata: {}
        created_at: "2026-10-17T18:00:00Z"
    Account:
      summary: A platform account
      value:
        id: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        object: account
        livemode: true
        name: Northlight
        types: [platform]
        capabilities: [hold_licenses, request_licenses, run_checks, act_for_licensees]
        status: active
        api_version: "2026-10-15"
        platform:
          display_name: Northlight
          url: https://northlight.example
          client_id: cl_064fvt404z82ymdspje0ggaztt
        created_at: "2026-09-02T14:20:00Z"
    Talent:
      summary: A talent
      value:
        id: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        object: talent
        livemode: true
        name: Maya Okafor
        aliases: [Maya O.]
        status: active
        verification: { verified: true, method: id_document, verified_at: "2026-06-11T09:30:00Z" }
        protection: { references: true, modalities: [image, video, speech] }
        posture:
          default: license_required
          accepts_requests: true
          rules:
            - { purpose: political, declaration: prohibited }
            - { kind: endorsement, purpose: advertising, declaration: license_required }
            - modality: text
              kind: reference
              declaration: allowed
              obligations: []
        representation:
          - account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
            name: Summit Talent Management
            role: manager
            powers: [issue_licenses, review_outputs, revoke, receive_statements]
        facets:
          - { id: fct_5zba2q8v1m3n7p4r6s9t0wxyhk, type: likeness, label: Studio likeness, status: ready }
          - { id: fct_v1m3n7p4r6s9t0wxyhk5zba2q8, type: voice, label: Speaking voice, status: ready }
          - { id: fct_q4r6s9t0wxyhk5zba2q8v1m3n7, type: name, label: Name, status: ready }
        hcs_subject_id: null
        profile_url: https://app.reflections.ai/t/maya-okafor
        created_at: "2026-06-11T09:00:00Z"
        updated_at: "2026-10-01T12:00:00Z"
    Facet:
      summary: A voice facet
      value:
        id: fct_v1m3n7p4r6s9t0wxyhk5zba2q8
        object: facet
        livemode: true
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        type: voice
        label: Speaking voice
        status: ready
        modalities: [speech]
        material: { items: 12, updated_at: "2026-09-20T10:00:00Z" }
        provider_bindings:
          - { provider: example-voice-provider, kind: voice, external_id: vx_4f9a2c, status: active }
        created_at: "2026-06-12T09:00:00Z"
        updated_at: "2026-09-20T10:00:00Z"
    Resolution:
      summary: One name matched
      value:
        id: res_m3n7p4r6s9t0wxyhk5zba2q8v1
        object: resolution
        livemode: true
        status: matched
        candidates:
          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            name: Maya Okafor
            matched_by: name
            confidence: high
            span: { input: 0, start: 24, end: 35, text: Maya Okafor }
            licensed: true
            declaration: license_required
        use_kind: impersonation
        created_at: "2026-10-17T18:00:00Z"
    License:
      summary: An active license
      value:
        id: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
        object: license
        livemode: true
        status: active
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        issued_by: { party: talent, account: null }
        handle: K7Q4M2
        current_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
        revision_number: 1
        pending_revision: null
        terms_digest: "sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431"
        scope:
          facets: [fct_5zba2q8v1m3n7p4r6s9t0wxyhk]
          modalities: [image]
          kinds: [depiction]
          purposes: [advertising]
          commercial: true
          channels: [social, web]
          territories: [US, CA]
          window: { starts_at: "2026-10-01T00:00:00-04:00", ends_at: "2027-03-31T00:00:00-04:00", time_zone: America/New_York }
          adjustments:
            reframe: true
            background_extension: true
            lighting: true
            text_overlay: true
            body_and_age: false
            expression: false
            hair: false
            pose: false
            wardrobe: true
            objects: true
            skin_retouch: false
            endorsement: false
          prohibited_changes: [body_and_age, expression, hair, pose, skin_retouch, endorsement]
          required_attributes: [identity.samePerson, appearance.bodyAndAge, appearance.expression, appearance.hair, appearance.pose, appearance.skinRetouch, context.endorsement]
          rules:
            never: [Do not show alcohol or tobacco.]
            always: []
            brief: null
          release_policy: per_output_review
          escalation_window: P7D
          final_deliverables: 24
          sessions: { permitted: false }
          material_access: []
          platforms: { mode: any_connected, accounts: [] }
          sublicense: none
          training: prohibited
          disclosure: brand
          attribution: null
          post_revocation: { policy: retain }
          exclusivity: { exclusive: false, category: null }
          conflicts: []
          compensation:
            type: per_unit
            per_unit: { units: placements, rate: { amount: 25000, currency: usd }, per: 1 }
            minimum: { amount: 500000, currency: usd }
            schedule: monthly
        acceptance_url: null
        accepted_at: "2026-09-28T16:02:00Z"
        suspended_at: null
        revoked_at: null
        declined_at: null
        metadata: {}
        created_at: "2026-09-27T11:15:00Z"
    LicenseRevision:
      summary: A signed revision
      value:
        id: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
        object: license_revision
        livemode: true
        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
        number: 1
        status: current
        source_kind: issue
        terms:
          releasePolicy: perOutputTalentReview
          adjustments: { reframe: true, backgroundExtension: true, lighting: true, textOverlay: true, bodyAndAge: false, expression: false, hair: false, pose: false, wardrobe: true, objects: true, skinRetouch: false, endorsement: false }
          channels: [social, web]
          territories: [US, CA]
          startsAt: "2026-10-01T00:00:00-04:00"
          endsAt: "2027-03-31T00:00:00-04:00"
          windowTimeZone: America/New_York
          requiredAttributes: [identity.samePerson, appearance.bodyAndAge, appearance.expression, appearance.hair, appearance.pose, appearance.skinRetouch, context.endorsement]
          prohibitedChanges: [bodyAndAge, expression, hair, pose, skinRetouch, endorsement]
          neverExtras: [Do not show alcohol or tobacco.]
          finalDeliverables: 24
          isExclusive: false
        terms_digest: "sha256:39f18c8bef02b5226b9feaa92e526ed30b81b91650d8a10b503281b169f44431"
        canonicalization: tlp-json-1
        scope:
          channels: [social, web]
          territories: [US, CA]
          release_policy: per_output_review
        enforcement:
          - { term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.channels", enforcement: checked, stage: [check] }
          - { term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.requiredAttributes", enforcement: checked, stage: [generation] }
          - { term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras", enforcement: checked, stage: [check, generation] }
          - { term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.isExclusive", enforcement: recorded, stage: [] }
        signatures:
          - { party: talent, account: null, name: Maya Okafor, method: passkey, signed_at: "2026-09-27T11:15:00Z" }
          - { party: licensee, account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba, name: Ridgeline, method: passkey, signed_at: "2026-09-28T16:02:00Z" }
        document_url: https://app.reflections.ai/l/K7Q4M2/revisions/1
        created_at: "2026-09-27T11:15:00Z"
    DiscoveryDocument:
      summary: The Reflections discovery document
      value:
        issuer: https://app.reflections.ai
        protocol: tlp
        protocol_versions: ["1.0"]
        api_base: https://app.reflections.ai/v1
        api_versions: ["2026-10-15"]
        jwks_uri: https://app.reflections.ai/.well-known/jwks.json
        check_endpoint: https://app.reflections.ai/v1/checks
        generation_endpoint: https://app.reflections.ai/v1/generations
        session_endpoint: https://app.reflections.ai/v1/sessions
        verification_endpoint: https://app.reflections.ai/v1/verifications
        receipt_endpoint: "https://app.reflections.ai/v1/receipts/{receipt_id}"
        revocation_feed: https://app.reflections.ai/v1/revocations
        talent_index: https://app.reflections.ai/v1/talent/index
        authorization_endpoint: https://app.reflections.ai/oauth/authorize
        token_endpoint: https://app.reflections.ai/oauth/token
        introspection_endpoint: https://app.reflections.ai/oauth/introspect
        mcp_endpoint: https://app.reflections.ai/mcp
        receipt_page: "https://app.reflections.ai/r/{receipt_id}"
        token_types: [tlp-auth+jwt, tlp-session+jwt, tlp-receipt+jwt]
        obligation_types: [generation_check, hold_until_release, draft_watermark, generation_instructions, disclosure, attribution, c2pa_manifest, no_training, delete_material, usage_report]
        c2pa_assertion_label: ai.reflections.license
    Jwks:
      summary: The current, retired and test keys
      value:
        keys:
          - { kty: EC, crv: P-256, kid: rfl-2026-10-docs3, use: sig, alg: ES256, x: ZoYofSbzIa2end2Uk8RWL2lqZA8h1yhqDUPTdAeguns, "y": ufMrUfKD5j5lbepL80bq9gxm81nQ0Zy0n8ABI5ZorZ0 }
          - { kty: EC, crv: P-256, kid: rfl-2026-04-docs3, use: sig, alg: ES256, x: smCKFBms8rHn_zcLkGN7leNXC0Kw0tMUos5Ptq3vTP8, "y": aXhqxlAT_XFcwIvpRfcQ3_F-osigj44ekOnIjTBcoRw }
          - { kty: EC, crv: P-256, kid: rfl-test-2026-10-docs3, use: sig, alg: ES256, x: olA2YiuvUovqtC-h3GQzdrJtqrG0cyh1YPgnzrBjVy8, "y": D7LpiphUIzpegpDaxDAj9NDmXi4ht4ADhSlphr8JCBc }
    AuthorizationServerMetadata:
      summary: The Reflections authorization server
      value:
        issuer: https://app.reflections.ai
        authorization_endpoint: https://app.reflections.ai/oauth/authorize
        token_endpoint: https://app.reflections.ai/oauth/token
        registration_endpoint: https://app.reflections.ai/oauth/register
        introspection_endpoint: https://app.reflections.ai/oauth/introspect
        revocation_endpoint: https://app.reflections.ai/oauth/revoke
        scopes_supported: [talent:read, licenses:read, license_requests:write, files:write, checks:write, generations:write, sessions:write, revocations:write, usage:write, statements:read]
        response_types_supported: [code]
        response_modes_supported: [query]
        grant_types_supported: [authorization_code, refresh_token, client_credentials]
        token_endpoint_auth_methods_supported: [none, client_secret_basic, client_secret_post]
        introspection_endpoint_auth_methods_supported: [client_secret_basic, client_secret_post]
        revocation_endpoint_auth_methods_supported: [none, client_secret_basic, client_secret_post]
        code_challenge_methods_supported: [S256]
        authorization_response_iss_parameter_supported: true
        client_id_metadata_document_supported: true
        service_documentation: https://docs.reflections.ai/api-reference/authentication
    ProtectedResourceMetadata:
      summary: The MCP server
      value:
        resource: https://app.reflections.ai/mcp
        resource_name: Reflections Talent API
        authorization_servers: [https://app.reflections.ai]
        scopes_supported: [talent:read, licenses:read, checks:write, generations:write, license_requests:write, usage:write]
        bearer_methods_supported: [header]
        resource_documentation: https://docs.reflections.ai/api-reference/mcp/overview
    Receipt:
      summary: A generation receipt
      value:
        id: rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
        object: receipt
        livemode: true
        kind: generation
        subject: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
        decision: allow
        assurance: observed
        talent: [tal_9t0wxyhk5zba2q8v1m3n7p4r6s]
        licenses:
          - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
            license_revision: lrv_7p4r6s9t0wxyhk5zba2q8v1m3n
            terms_digest: "sha256:8e0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a"
        licensee: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        request_digest: "sha256:d4f6b8a0c2e4d6f8b0a2c4e6d8f0b2a4c6e8d0f2b4a6c8e0d2f4b6a8c0e2d4f6"
        artifact_sha256: 3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d
        permitted_use:
          modality: speech
          purpose: branded_content
          channels: [audio, web]
          territories: [US]
          ends_at: "2027-06-30T23:59:59Z"
        obligations:
          - { type: disclosure, level: licensed, placement: metadata, text: "AI voice of Maya Okafor, licensed." }
          - { type: c2pa_manifest }
          - { type: usage_report, units: seconds, within: P1D }
        use_status: permitted
        use_status_changed_at: null
        jws: "eyJhbGciOiJFUzI1NiIsImtpZCI6InJmbC0yMDI2LTEwLWRvY3MzIiwidHlwIjoidGxwLXJlY2VpcHQrand0In0.eyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fQ.K7AXwiCTQv-GS_xfIdystUTVdNl6u7p0FQ9XSkoh5amUnEehLLLpriZk7OA38gBo5UZHItmJm0rHf_8Eebj2rg"
        cose: "0oRYKKMBJgNwYXBwbGljYXRpb24vanNvbgRRcmZsLTIwMjYtMTAtZG9jczOgWQRUeyJpYXQiOjE3OTIyNjAzNjMsImlzcyI6Imh0dHBzOi8vYXBwLnJlZmxlY3Rpb25zLmFpIiwianRpIjoicmNwdF9oazV6YmEycTh2MW0zbjdwNHI2czl0MHd4eSIsInN1YiI6Imdlbl8ycTh2MW0zbjdwNHI2czl0MHd4eWhrNXpiYSIsInRscCI6eyJhcnRpZmFjdF9zaGEyNTYiOiIzYjVkN2Y5YTFjM2U1YjdkOWYxYTNjNWU3YjlkMWYzYTVjN2U5YjFkM2Y1YTdjOWUxYjNkNWY3YTljMWUzYjVkIiwiYXNzdXJhbmNlIjoib2JzZXJ2ZWQiLCJkZWNpc2lvbiI6ImFsbG93Iiwia2luZCI6ImdlbmVyYXRpb24iLCJsaWNlbnNlZSI6ImFjY3RfN3A0cjZzOXQwd3h5aGs1emJhMnE4djFtM24iLCJsaWNlbnNlcyI6W3sibGljZW5zZSI6ImxpY19iYTJxOHYxbTNuN3A0cjZzOXQwd3h5aGs1eiIsInJldmlzaW9uIjoibHJ2XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwidGFsZW50IjoidGFsXzl0MHd4eWhrNXpiYTJxOHYxbTNuN3A0cjZzIiwidGVybXNfZGlnZXN0Ijoic2hhMjU2OjhlMGEyYzRlNmI4ZDBmMmE0YzZlOGIwZDJmNGE2YzhlMGIyZDRmNmE4YzBlMmI0ZDZmOGEwYzJlNGI2ZDhmMGEifV0sIm9ibGlnYXRpb25zIjpbeyJsZXZlbCI6ImxpY2Vuc2VkIiwicGxhY2VtZW50IjoibWV0YWRhdGEiLCJ0ZXh0IjoiQUkgdm9pY2Ugb2YgTWF5YSBPa2Fmb3IsIGxpY2Vuc2VkLiIsInR5cGUiOiJkaXNjbG9zdXJlIn0seyJ0eXBlIjoiYzJwYV9tYW5pZmVzdCJ9LHsidHlwZSI6InVzYWdlX3JlcG9ydCIsInVuaXRzIjoic2Vjb25kcyIsIndpdGhpbiI6IlAxRCJ9XSwicGxhdGZvcm0iOiJhY2N0XzdwNHI2czl0MHd4eWhrNXpiYTJxOHYxbTNuIiwicmVxdWVzdF9kaWdlc3QiOiJzaGEyNTY6ZDRmNmI4YTBjMmU0ZDZmOGIwYTJjNGU2ZDhmMGIyYTRjNmU4ZDBmMmI0YTZjOGUwZDJmNGI2YThjMGUyZDRmNiIsInRhbGVudCI6WyJ0YWxfOXQwd3h5aGs1emJhMnE4djFtM243cDRyNnMiXSwidXNlIjp7ImNoYW5uZWxzIjpbImF1ZGlvIiwid2ViIl0sImNvbW1lcmNpYWwiOnRydWUsImtpbmQiOiJpbXBlcnNvbmF0aW9uIiwibW9kYWxpdHkiOiJzcGVlY2giLCJwdXJwb3NlIjoiYnJhbmRlZF9jb250ZW50IiwidGVycml0b3JpZXMiOlsiVVMiXX0sInZlciI6IjEuMCJ9fVhAEi6bheTmJljXxlJ+XC0MOy1e3me3kO2Y1CL98qTItHFC4zoFX2kUZ8IE5cQEO46iM25l/wOlUdOFsTMzzgiBwQ=="
        page_url: https://app.reflections.ai/r/rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
        issued_at: "2026-10-17T18:06:03Z"
    Verification:
      summary: A file matched by its manifest
      value:
        id: vrf_8b0c2d4e6f8g0h2j4k6m8n0p2q
        object: verification
        result: verified
        method: manifest
        match: null
        manifest: { signer: Northlight, assertion_present: true, signature_valid: true }
        receipt:
          id: rcpt_hk5zba2q8v1m3n7p4r6s9t0wxy
          object: receipt
          livemode: true
          kind: generation
          subject: gen_2q8v1m3n7p4r6s9t0wxyhk5zba
          decision: allow
          assurance: observed
          talent: [tal_9t0wxyhk5zba2q8v1m3n7p4r6s]
          licenses:
            - talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
              license: lic_ba2q8v1m3n7p4r6s9t0wxyhk5z
              license_revision: lrv_7p4r6s9t0wxyhk5zba2q8v1m3n
              terms_digest: "sha256:8e0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a"
          request_digest: "sha256:d4f6b8a0c2e4d6f8b0a2c4e6d8f0b2a4c6e8d0f2b4a6c8e0d2f4b6a8c0e2d4f6"
          jws: "eyJhbGciOiJFUzI1NiIs…"
          use_status: permitted
          issued_at: "2026-10-17T18:06:03Z"
        detail: null
        created_at: "2026-10-18T09:12:44Z"
    Revocation:
      summary: A license revoked, awaiting acknowledgement
      value:
        id: rvk_s9t0wxyhk5zba2q8v1m3n7p4r6
        object: revocation
        livemode: true
        scope: license
        targets:
          talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
          licenses: [lic_ba2q8v1m3n7p4r6s9t0wxyhk5z]
          facets: [fct_v1m3n7p4r6s9t0wxyhk5zba2q8]
          mandate: null
        status: pending_acknowledgement
        initiated_by: talent
        for_cause: false
        cause: null
        note: null
        effective_at: "2026-10-17T18:03:40Z"
        post_revocation: { policy: retain, withdraw_by: null }
        required_actions: [stop_generation, purge_cached_decisions, delete_provider_copies]
        provider_copies:
          - { facet: fct_v1m3n7p4r6s9t0wxyhk5zba2q8, provider: example-voice-provider, external_id: vx_4f9a2c }
        affected: { checks_denied: 3, generations_denied: 0, sessions_terminated: 1, released_outputs: 418 }
        acknowledge_by: "2026-10-18T18:03:40Z"
        acknowledgements: []
        created_at: "2026-10-17T18:03:40Z"
    Statement:
      summary: An issued monthly statement
      value:
        id: stmt_0c2e4g6j8k0m2n4p6q8r0s2t4v
        object: statement
        livemode: true
        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        status: issued
        period: { start: "2026-10-01T00:00:00Z", end: "2026-11-01T00:00:00Z" }
        currency: usd
        lines:
          - description: Placements, social and web
            units: placements
            reported: 30
            observed: 32
            billable: 32
            rate: { amount: 25000, currency: usd }
            amount: 800000
        amount_due: 800000
        amount_paid: 0
        reconciliation: { result: under_reported, detail: "32 released outputs were placed; 30 were reported." }
        payments: []
        due_at: "2026-11-30T23:59:59Z"
        issued_at: "2026-11-02T08:00:00Z"
        document_url: https://app.reflections.ai/statements/stmt_0c2e4g6j8k0m2n4p6q8r0s2t4v
        created_at: "2026-10-01T00:00:00Z"
    Mandate:
      summary: A manager's mandate
      value:
        id: mnd_7nb1ef0wykcj3mkwaba3x20ez6
        object: mandate
        livemode: true
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        talent_name: Maya Okafor
        representative: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
        role: manager
        powers: [issue_licenses, review_outputs, revoke, receive_statements]
        status: active
        starts_at: "2026-06-12T10:00:00Z"
        ends_at: null
        ended_at: null
        revocation: null
        created_at: "2026-06-12T10:00:00Z"
    EscalationOpen:
      summary: A rule that needs a person
      value:
        id: esc_t0wxyhk5zba2q8v1m3n7p4r6s9
        object: escalation
        livemode: true
        reason: judgment
        reviewer: talent
        status: open
        expires_at: "2026-10-24T18:04:00Z"
        resolved_at: null
        note: null
        subject: { object: check, id: chk_r6s9t0wxyhk5zba2q8v1m3n7p4 }
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        licensee_name: Ridgeline
        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        platform_name: Northlight
        use:
          modality: image
          kind: depiction
          purpose: advertising
          commercial: true
          channels: [social]
          territories: [US]
        inputs:
          - role: prompt
            text: Maya Okafor at a trailhead café with two friends, paper cups on the table, morning light
        reasons:
          - code: prohibited_custom_term
            stage: check
            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
            sentence: Do not show alcohol or tobacco.
        findings: []
        artifact: null
        request_digest: "sha256:c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5"
        review_url: https://app.reflections.ai/review/esc_t0wxyhk5zba2q8v1m3n7p4r6s9
        decision: null
        decided_by: null
        created_at: "2026-10-17T18:04:00Z"
    EscalationAllowed:
      summary: Allowed by the talent's manager
      value:
        id: esc_t0wxyhk5zba2q8v1m3n7p4r6s9
        object: escalation
        livemode: true
        reason: judgment
        reviewer: talent
        status: allowed
        expires_at: "2026-10-24T18:04:00Z"
        resolved_at: "2026-10-17T21:30:00Z"
        note: Fine as long as the cups hold coffee.
        subject: { object: check, id: chk_r6s9t0wxyhk5zba2q8v1m3n7p4 }
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
        license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        licensee_name: Ridgeline
        platform: acct_7p4r6s9t0wxyhk5zba2q8v1m3n
        platform_name: Northlight
        use:
          modality: image
          kind: depiction
          purpose: advertising
          commercial: true
          channels: [social]
          territories: [US]
        inputs:
          - role: prompt
            text: Maya Okafor at a trailhead café with two friends, paper cups on the table, morning light
        reasons:
          - code: prohibited_custom_term
            stage: check
            talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
            term: "license:lic_k5zba2q8v1m3n7p4r6s9t0wxyh/terms.neverExtras"
            sentence: Do not show alcohol or tobacco.
        findings: []
        artifact: null
        request_digest: "sha256:c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5"
        review_url: null
        decision: allow
        decided_by: { party: representative, account: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b, name: Lena Brooks }
        created_at: "2026-10-17T18:04:00Z"
    LicenseDraft:
      summary: A renewal waiting for the talent's signature
      value:
        id: ldr_hz4ngq81vhagynxm3ds9q2acz4
        object: license_draft
        livemode: true
        status: open
        kind: renew
        talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s
        licensee: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh
        license_request: null
        scope:
          facets: [fct_5zba2q8v1m3n7p4r6s9t0wxyhk]
          modalities: [image]
          kinds: [depiction]
          purposes: [advertising]
          commercial: true
          channels: [social, web]
          territories: [US, CA]
          window: { starts_at: "2027-04-01T00:00:00-04:00", ends_at: "2027-09-30T00:00:00-04:00", time_zone: America/New_York }
          adjustments:
            reframe: true
            background_extension: true
            lighting: true
            text_overlay: true
            body_and_age: false
            expression: false
            hair: false
            pose: false
            wardrobe: true
            objects: true
            skin_retouch: false
            endorsement: false
          prohibited_changes: [body_and_age, expression, hair, pose, skin_retouch, endorsement]
          required_attributes: [identity.samePerson, appearance.bodyAndAge, appearance.expression, appearance.hair, appearance.pose, appearance.skinRetouch, context.endorsement]
          rules:
            never: [Do not show alcohol or tobacco.]
            always: []
            brief: null
          release_policy: per_output_review
          escalation_window: P7D
          final_deliverables: 24
          sessions: { permitted: false }
          material_access: []
          platforms: { mode: any_connected, accounts: [] }
          sublicense: none
          training: prohibited
          disclosure: brand
          attribution: null
          post_revocation: { policy: retain }
          exclusivity: { exclusive: false, category: null }
          conflicts: []
          compensation:
            type: per_unit
            per_unit: { units: placements, rate: { amount: 25000, currency: usd }, per: 1 }
            minimum: { amount: 500000, currency: usd }
            schedule: monthly
        terms_digest: "sha256:d499df2ff47603a092c7a59be9e329a344e6c23590c1ddfdbe6fc5a0ea32274b"
        signer: talent
        signing_url: https://app.reflections.ai/sign/ldr_hz4ngq81vhagynxm3ds9q2acz4
        signed_as_drafted: null
        license_revision: null
        decision_note: null
        note: Spring and summer 2027, on the same terms.
        created_by: acct_6m8n0p2q4r6s8t0v2w4x6y8z0b
        expires_at: "2026-11-16T09:00:00Z"
        signed_at: null
        declined_at: null
        metadata: {}
        created_at: "2026-10-17T09:00:00Z"
    RevocationByRepresentative:
      summary: A test license revoked by a representative
      value:
        id: rvk_1dxf6bkeqxsyw32j28wymgav5q
        object: revocation
        livemode: false
        scope: license
        targets:
          talent: tal_4n6p8r0t2v4x6z8b0d2f4h6j8k
          licenses: [lic_31x87g772xdcz1n1za29601rbt]
          facets: []
          mandate: null
        status: pending_acknowledgement
        initiated_by: representative
        for_cause: false
        cause: null
        note: The campaign ended early.
        effective_at: "2026-10-17T19:12:05Z"
        post_revocation: { policy: retain, withdraw_by: null }
        required_actions: [stop_generation, purge_cached_decisions]
        provider_copies: []
        affected: { checks_denied: 0, generations_denied: 2, sessions_terminated: 0, released_outputs: 5 }
        acknowledge_by: "2026-10-18T19:12:05Z"
        acknowledgements: []
        created_at: "2026-10-17T19:12:05Z"
    WebhookEndpoint:
      summary: A new endpoint, with its secret
      value:
        id: we_5x7z9b1d3f5h7k9m1p3r5t7v9x
        object: webhook_endpoint
        livemode: true
        url: https://northlight.example/webhooks/reflections
        events: [check.resolved, generation.released, generation.denied, revocation.created, session.terminated]
        description: Production
        status: enabled
        disabled_reason: null
        api_version: "2026-10-15"
        connected: true
        secret: whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw
        metadata: {}
        created_at: "2026-10-17T17:40:00Z"
    CheckResolvedEvent:
      summary: check.resolved
      value:
        id: evt_1h3k5m7p9r1t3v5x7z9b1d3f5h
        object: event
        type: check.resolved
        api_version: "2026-10-15"
        livemode: true
        account: acct_2q8v1m3n7p4r6s9t0wxyhk5zba
        sequence: 2
        created_at: "2026-10-17T21:30:01Z"
        data:
          object:
            id: chk_r6s9t0wxyhk5zba2q8v1m3n7p4
            object: check
            livemode: true
            status: allowed
            decision: allow
            talent:
              - { talent: tal_9t0wxyhk5zba2q8v1m3n7p4r6s, name: Maya Okafor, matched_by: name, confidence: high, decision: allow, license: lic_k5zba2q8v1m3n7p4r6s9t0wxyh, license_revision: lrv_p4r6s9t0wxyhk5zba2q8v1m3n7, escalation: esc_t0wxyhk5zba2q8v1m3n7p4r6s9 }
            use: { modality: image, kind: depiction, purpose: advertising, commercial: true, channels: [social], territories: [US] }
            reasons: []
            obligations: [{ type: generation_check, required: all }]
            authorization: { token: "eyJhbGciOiJFUzI1NiIs…", max_generations: 4, generations_used: 0, expires_at: "2026-10-17T21:45:00Z" }
            escalation: { id: esc_t0wxyhk5zba2q8v1m3n7p4r6s9, reason: judgment, reviewer: talent, status: allowed, expires_at: "2026-10-24T18:04:00Z", resolved_at: "2026-10-17T21:30:00Z", note: Fine as long as the cups hold coffee. }
            request_digest: "sha256:c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5"
            created_at: "2026-10-17T18:04:00Z"
          previous_attributes:
            status: escalated
            decision: escalate
