# ===========================================================================
# Prezent Platform API — OpenAPI 2.0 (v2)
#
# GENERATED FILE — do not edit by hand.
#
# Built from openapi.yaml (the 1.0 spec) by dropping the v1 AutoGenerator
# and v1 streams paths and splicing in the v2 surface, so every SHARED
# section (Template Converter, Audiences, Themes, Upload, File Access,
# Webhooks, Health) is guaranteed identical between the two versions.
#
# To change a shared section: edit openapi.yaml, then re-run the generator.
# To change the v2 AutoGenerator surface: edit the v2_*.yaml fragments.
# Generator + fragments live in scripts/openapi-v2/.
# ===========================================================================
openapi: 3.1.0
info:
  title: Prezent Platform API
  version: 2.0.0
  summary: Agent-ready REST API for Prezent's content-generation and template-conversion services.
  description: "The Prezent Platform API exposes Prezent's AI Builder, Template Converter,\nAudiences,\
    \ Themes, and File-upload services as a JSON HTTP API.\n\n**Only the AI Builder surface changed from\
    \ 1.0.** Template Converter,\nAudiences, Themes, Upload, File Access, Webhooks, and Health are identical\
    \ to\n1.0 — the same paths, payloads, and responses. If you use only those, 2.0\nrequires no change\
    \ on your side.\n\n**The AI Builder API moved from a polling model to a streaming one.**\n`POST /api/v2/generate`\
    \ (or `/autogenerator/edit`) returns a `callback_id`;\n`POST /api/v2/streams/sessions` with that id\
    \ returns a short-lived\n`stream_url`; opening it with any SSE client yields events shaped\n`{status,\
    \ message, callback_id}` — `status: \"inprogress\"` until a terminal\n`success`, `failed`, or `cancelled`,\
    \ with a successful terminal event adding\n`download_url`. `POST /api/v2/autogenerator/download` skips\
    \ the\n`streams/sessions` step and returns a `stream_url` directly, because the file\nmay need exporting\
    \ first and that can outlast an HTTP response. Stream URLs\nexpire in about 5 minutes with the token\
    \ embedded in the URL (so no\n`Authorization` header is sent, and `EventSource` cannot send one);\
    \ mint a\nfresh one by repeating the call — the stream replays from the start of the\nturn. There\
    \ is no status endpoint in 2.0, and the former regenerate /\nnode-change / slide-actions endpoints\
    \ collapsed into the single\n`POST /api/v2/autogenerator/edit`. A full walk-through with client code\
    \ is in\nthe [Streaming guide](/docs/streaming).\n\n**Success shapes are not uniform on the v2 AI\
    \ Builder surface** — read the\nresponse schema on the endpoint you are calling rather than assuming\
    \ a shared\nshape. `POST /api/v2/generate` and `/autogenerator/edit` return\n`{message, resData, error}`;\
    \ `/autogenerator/download` returns flat top-level\nfields; `/streams/sessions` returns `{success,\
    \ data}`;\n`/autogenerator/languages` returns `{status, message, data}`; and\n`/integrations/auth`\
    \ returns one of two shapes documented on that endpoint.\nErrors remain uniform everywhere: `{ \"\
    success\": false, \"data\": null, \"error\":\n{ \"code\": \"...\", \"message\": \"...\", \"details\"\
    : { } } }`. Error codes are drawn\nfrom a stable catalog (see `ErrorCode`) — codes never change meaning\
    \ or HTTP\nstatus once published. Schemas allow additional properties, so handlers may\nemit extra\
    \ keys alongside the documented ones; do not depend on undocumented\nkeys.\n\n**Conventions that apply\
    \ to every endpoint** (full reference in the companion\nguides on this documentation site):\n\n- **Auth:**\
    \ API key as a Bearer token — `Authorization: Bearer <key>`. Each\n  key is scoped to an allow-list\
    \ of endpoint paths; an out-of-scope call\n  returns `404 ENDPOINT_NOT_FOUND`, indistinguishable from\
    \ a path that does\n  not exist.\n- **Rate limits:** gateway throttle 10 req/s sustained, 5 burst,\n\
    \  1,000 req/day per key; per-company per-category 60-second sliding windows;\n  annual quotas (50,000\
    \ slide generations/yr, 1,000,000 downloads/yr). Limit\n  breaches return `429` with `error.code`\
    \ `TOO_MANY_REQUESTS` (gateway),\n  `RATE_LIMIT_EXCEEDED` (per-category), or `USAGE_LIMIT_EXCEEDED`\
    \ (annual).\n- **Idempotency & pagination:** mutating requests accept an\n  `Idempotency-Key`; list\
    \ endpoints accept opt-in `limit`/`cursor` paging.\n\n**Still on 1.0?** The 1.0 contract is unchanged\
    \ and still served — see the\n[1.0 API reference](/api-reference/) and the [1.0 documentation](/docs/1.0/).\n\
    Both versions run side by side; there is no forced migration.\n\n**Building with an AI agent?** Prezent\
    \ ships a first-class Model Context\nProtocol (MCP) server. The hosted endpoint is `https://mcp.myprezent.com/mcp`\n\
    (OAuth 2.1, works with Claude.ai Custom Connectors); a local stdio server is\npublished on PyPI as\
    \ `prezent-mcp-server` and plugs into Claude Desktop,\nCursor, Cline, Continue, and Zed. The MCP tools\
    \ wrap the same REST endpoints\ndescribed here.\n\n**Official SDKs.** Typed REST clients are published\
    \ for Python and\nTypeScript (`prezent-sdk`) — generated from and versioned against this spec.\nFor\
    \ other languages, generate a client from this document.\n\n**Out of scope of this document:** SCIM\
    \ endpoints under `/api/v1/scim/*`.\nThose endpoints conform to RFC 7644 (SCIM 2.0) and follow a different\n\
    envelope (`schemas`, `Resources`, `totalResults`, etc.). They are documented\nseparately at /docs/scim-user-management.\n"
  x-out-of-scope-note: 'SCIM endpoints (`/api/v1/scim/*`) are NOT included in this spec. They

    follow RFC 7644 (SCIM 2.0) and are documented in a separate document at

    /docs/scim-user-management.

    '
  contact:
    name: Prezent API Support
    email: support@prezent.ai
    url: https://prezent.ai
  license:
    name: Proprietary - Prezent, Inc.
    url: https://prezent.ai/terms
servers:
- url: https://api.prezent.ai
  description: Production (canonical)
- url: https://uatstage-api.myprezent.com
  description: UAT (user acceptance testing)
- url: https://devstage-api.myprezent.com
  description: Development
security:
- BearerAuth: []
tags:
- name: AI Builder
  description: 'Generate, edit, and download AI-authored presentations. In API 2.0 every one of these
    is a STREAMING flow: the endpoint returns a callback_id (or, for download, a stream_url directly),
    and progress plus the final download URL arrive as Server-Sent Events. See the [AI Builder API guide](/docs/auto-generate).'
- name: Template Converter
  description: Apply a target brand template to an uploaded presentation, including review suggestions,
    work-area adjustment, layout change, and download.
- name: Audiences
  description: List and search the audience profiles configured for the caller's company.
- name: Themes
  description: List the presentation themes (brand templates) configured for the caller's company.
- name: Upload
  description: Validate, preprocess, and upload supporting files (PowerPoint, PDF, images, etc.).
- name: File Access
  description: Mint short-lived access tokens for the caller's stored files.
- name: Webhooks
  description: Receive signed HTTPS callbacks when Prezent jobs complete or fail. Subscriptions are scoped
    per API key, retried over a 21h window, and auto-disabled after 50 consecutive failures. See the [Webhooks
    guide](/docs/webhooks) for the signature format and verification examples.
- name: Streaming
  description: Mint a short-lived, authenticated Server-Sent Events URL for a callback_id returned by
    generate or edit. The stream carries progress events and delivers the download URL on its terminal
    event. See the [Streaming guide](/docs/streaming).
- name: Integrations
  description: Connect third-party apps (Google Drive, Notion, …) to the caller's Prezent account so the
    generator can pull context from them. Connect once, then reference the app in a prompt.
- name: Health
  description: Liveness and component health-check endpoints.
paths:
  /api/v2/generate:
    post:
      tags:
      - AI Builder
      operationId: createGenerationV2
      summary: Generate a presentation
      description: "Start a presentation generation and receive a `callback_id`.\n\nThis is a **streaming**\
        \ flow. Nothing is returned but the id — to watch\nprogress and obtain the finished deck, exchange\
        \ the `callback_id` for a\nstream URL via\n[`POST /api/v2/streams/sessions`](#operation/createStreamSessionV2)\n\
        and read the Server-Sent Events. The terminal `done` event carries the\n`download_url`.\n\n###\
        \ Providing context\n\nBeyond `prompt`, you can ground the generation in your own material:\n\n\
        - `files` — ids of previously uploaded files (see\n  [`POST /api/v1/preprocess`](#operation/preprocessFile))\n\
        - `web_links` — URLs to read\n- `text` — an inline block of text\n\n### Settings resolution\n\n\
        Every key in `settings` is optional. Any key you omit falls back to the\ndefault stored on your\
        \ API key, and then to the documented default. So a\nkey configured with your house template and\
        \ language needs only a\n`prompt`.\n"
      security:
      - BearerAuth: []
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenerateV2Request'
            examples:
              minimal:
                summary: Prompt only — everything else from your key's defaults
                value:
                  prompt: A 10-slide deck on renewable-energy market trends for 2026
              withContext:
                summary: Grounded in an uploaded file, a web link, and inline text
                value:
                  prompt: Summarise our Q3 results and compare them to the market
                  files:
                  - file_id: 7f1c9a52-3e44-4a1b-9c88-2d5e6f0a1b23
                  web_links:
                  - https://example.com/market-report-2026
                  text: Our internal target was 12% growth in the EMEA region.
              fullSettings:
                summary: Every supported setting, with all accepted values shown
                value:
                  prompt: A 12-slide investor update on our AI platform
                  template_id: your-template-id
                  audience_id: 9b2e1f74-55aa-4c0d-8f31-6ab7c9d20e15
                  websearch: true
                  settings:
                    template_id: your-template-id
                    language: en
                    websearch: true
                    add_sources_to_footer: true
                    add_sources_to_slides_note: false
                    generate_speaker_notes: true
                    add_speaker_notes_to_slides_note: false
                    image_library:
                      brand_library: false
                      prezent_library: true
                      ai_images: true
                      my_workspace: false
                      additional_context: false
                    voice_settings:
                      type: standard
                    deck_default_size: 10
                    deck_max_size: 20
                    export_type: pptx
                    enable_mcp_context: true
      responses:
        '200':
          description: 'Generation accepted. `resData.callback_id` identifies this

            generation — pass it to `POST /api/v2/streams/sessions` to stream

            the result.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GenerateV2Response'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: 'One or more request fields are invalid. `error.details` is an array

            of human-readable messages, one per failed field.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                data: null
                error:
                  code: INVALID_INPUT
                  message: The request contains invalid input.
                  details:
                  - prompt is required
                  - 'settings.language: ''xx'' is not a supported language locale'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/v2/autogenerator/edit:
    post:
      tags:
      - AI Builder
      operationId: editGenerationV2
      summary: Edit a presentation
      description: 'Apply a natural-language edit to a presentation that was generated with

        [`POST /api/v2/generate`](#operation/createGenerationV2).


        This is a **streaming** flow, and it works exactly like generate: you

        receive a **new** `callback_id` for this edit turn, which you exchange

        for a stream URL via

        [`POST /api/v2/streams/sessions`](#operation/createStreamSessionV2).


        Edits are conversational — each edit builds on the last. Pass the

        `callback_id` of the **most recent** turn (the original generation, or a

        previous edit) as the `callback_id` here, and use the **new** id returned

        for the next edit.


        Omit `slideIndex` to edit the deck as a whole; supply it to target one

        slide.


        > **The generation must have finished.** Editing is only possible once

        > the target presentation has completed — the deck size has to be known

        > before a slide can be addressed. Editing a `callback_id` that is still

        > generating returns `400`.


        > **One turn at a time.** If a previous turn on this presentation is

        > still running, the request is rejected with that condition reported in

        > `error.message`.

        '
      security:
      - BearerAuth: []
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EditV2Request'
            examples:
              wholeDeck:
                summary: Edit the whole deck
                value:
                  callback_id: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
                  prompt: Make the tone more formal and shorten every bullet
              singleSlide:
                summary: Edit one slide
                value:
                  callback_id: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
                  prompt: Replace the chart on this slide with a comparison table
                  slideIndex: 4
              withContext:
                summary: Edit with added context
                value:
                  callback_id: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
                  prompt: Update the revenue figures from the attached file
                  files:
                  - file_id: 7f1c9a52-3e44-4a1b-9c88-2d5e6f0a1b23
                  web_links:
                  - https://example.com/q4-results
                  text: Q4 revenue closed at $4.2M, up 18% year over year.
      responses:
        '200':
          description: 'Edit accepted. `resData.callback_id` is a **new** id for this edit

            turn — stream it, and use it as the `callback_id` for any subsequent

            edit.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EditV2Response'
        '400':
          description: 'The request is invalid, or the presentation is not in an editable

            state. `error.details` explains which. Common causes: the

            `callback_id` was not produced by generate or a prior edit; the

            generation has not finished yet; `slideIndex` is out of range; or a

            previous turn on this presentation is still running.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                notReady:
                  summary: Generation still in progress
                  value:
                    success: false
                    data: null
                    error:
                      code: BAD_REQUEST
                      message: Bad request.
                      details: The presentation for this callback_id is not ready yet; cannot edit slides
                        until generation completes
                slideOutOfRange:
                  summary: slideIndex past the end of the deck
                  value:
                    success: false
                    data: null
                    error:
                      code: BAD_REQUEST
                      message: Bad request.
                      details: slideIndex 12 is out of range; the presentation has 10 slide(s) (valid
                        range 0-9)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/v2/autogenerator/download:
    post:
      tags:
      - AI Builder
      operationId: downloadGenerationV2
      summary: Download a presentation
      description: 'Obtain the finished presentation file for a `callback_id`.


        This is a **streaming** flow, and it is the one place where it differs

        from generate and edit: this endpoint returns a **`stream_url`

        directly**, so there is no `POST /api/v2/streams/sessions` step. Open

        the URL and read the events; the terminal `done` event carries the

        `download_url`.


        A stream rather than an inline URL because the file may not exist yet.

        If the requested `export_type` is not the format this presentation

        already produced, a fresh export runs — which can take several minutes,

        far longer than an HTTP response allows. Both cases end on the same

        terminal event, so one parser handles either:


        | Case | What you see |

        |---|---|

        | Already exported in this format | `done` immediately, with the `download_url` |

        | Needs exporting | progress events, then `done` with the new `download_url` |


        > **Quota is checked up front.** If your plan does not have enough

        > remaining download slides for this presentation, the request fails

        > with `429 USAGE_LIMIT_EXCEEDED` and no stream is minted.

        '
      security:
      - BearerAuth: []
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DownloadV2Request'
            examples:
              default:
                summary: Default format (your key's configured default, else pptx)
                value:
                  callback_id: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
              asPdf:
                summary: Explicit format
                value:
                  callback_id: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
                  export_type: pdf
      responses:
        '200':
          description: 'A download stream was minted. Open `stream_url` and read the

            terminal `done` event for the `download_url`. The URL expires at

            `expires_at` — mint a new one by calling this endpoint again.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadV2Response'
        '400':
          description: 'The `callback_id` is missing, malformed, or has no active download

            session (sessions expire about 3 hours after generation), or

            `export_type` is not a supported value.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                data: null
                error:
                  code: BAD_REQUEST
                  message: Bad request.
                  details: No active download session was found for this callback_id
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          description: 'A rate limit was hit, or your plan has insufficient remaining

            download slides for this presentation

            (`error.code: USAGE_LIMIT_EXCEEDED`).

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                data: null
                error:
                  code: USAGE_LIMIT_EXCEEDED
                  message: Usage limit exceeded.
                  details: This presentation has 12 slide(s), but only 5 download slide(s) remain on your
                    plan (limit 50000).
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/v2/streams/sessions:
    post:
      tags:
      - Streaming
      operationId: createStreamSessionV2
      summary: Create a stream session
      description: 'Exchange a `callback_id` from

        [generate](#operation/createGenerationV2) or

        [edit](#operation/editGenerationV2) for an authenticated Server-Sent

        Events URL.


        Open the returned `stream_url` with any SSE client — the token is

        embedded in the URL, so no `Authorization` header is needed (and cannot

        be sent by `EventSource` anyway). Every event on the stream has the same

        shape, so one parser handles all of them:


        ```

        event: status

        data: {"status":"inprogress","message":"Analyzing the key elements","callback_id":"..."}

        ```


        `status` is `inprogress` on every progress event, and on the terminal

        event one of `success`, `failed`, or `cancelled`. A successful terminal

        event adds a `download_url`. The stream closes after it.


        The full event catalog, reconnection semantics, and client code samples

        are in the [Streaming guide](/docs/streaming).


        > **Short-lived.** The URL expires at `expires_at` (about 5 minutes).

        > Open it promptly; mint a new one by calling this endpoint again — the

        > stream replays from the start of the turn, so nothing is missed.


        > **Download is different.** `POST /api/v2/autogenerator/download`

        > returns its own `stream_url` and does not come through here.

        '
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StreamSessionV2Request'
            example:
              callback_id: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
      responses:
        '201':
          description: Stream session created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StreamSessionV2Response'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: 'No generation was found for this `callback_id` under your API key,

            or its session has expired (about 3 hours after generation).

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                data: null
                error:
                  code: STREAM_CALLBACK_NOT_FOUND
                  message: No stream session was found for this callback_id.
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/v2/autogenerator/languages:
    get:
      tags:
      - AI Builder
      operationId: listLanguagesV2
      summary: List supported languages
      description: 'The languages a presentation can be generated in. Pass a `locale` from

        this list as `settings.language` on

        [`POST /api/v2/generate`](#operation/createGenerationV2); an

        unsupported locale is rejected with `422`.


        The list is static — cache it rather than calling this on every

        generation.

        '
      security:
      - BearerAuth: []
      responses:
        '200':
          description: The supported languages.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LanguagesV2Response'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /api/v2/integrations/auth:
    get:
      tags:
      - Integrations
      operationId: getIntegrationAuthUrlV2
      summary: Connect an app
      description: 'Begin connecting a third-party app (Google Drive, Notion, …) to the

        caller''s Prezent account. Once connected, a generation can pull context

        from that app by setting `settings.enable_mcp_context` to `true` on

        [`POST /api/v2/generate`](#operation/createGenerationV2).


        **The response has two shapes**, depending on whether the app needs

        authorization:


        | App | Response |

        |---|---|

        | Requires authorization (OAuth etc.) | An authorization URL for the user to open |

        | Requires none | `{ "status": "connected" }` — already done, nothing to visit |


        For the first shape, send the user to the URL, let them authorize, then

        confirm with

        [`GET /api/v2/integrations/auth/status`](#operation/getIntegrationAuthStatusV2).


        Which shape applies is a property of the app, not something you choose.

        Branch on the presence of `status: "connected"`.


        > The connection is made for **the user who owns the API key**. There is

        > no parameter to connect an app on another user''s behalf.

        '
      security:
      - BearerAuth: []
      parameters:
      - name: mcp_id
        in: query
        required: true
        description: Identifier of the app to connect.
        schema:
          type: string
        example: google-drive
      responses:
        '200':
          description: 'Either an authorization URL to open, or a confirmation that the app

            is connected and needs no authorization.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntegrationAuthV2Response'
              examples:
                authRequired:
                  summary: Authorization needed — open the URL
                  value:
                    auth_url: https://accounts.google.com/o/oauth2/v2/auth?client_id=...&state=...
                connected:
                  summary: No authorization needed — already connected
                  value:
                    status: connected
                    message: MCP connection successful
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: No app is registered under this `mcp_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                success: false
                data: null
                error:
                  code: MCP_NOT_FOUND
                  message: The requested app was not found.
                  details:
                    mcp_id: google-drive
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          description: The integrations service is temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /api/v2/integrations/auth/status:
    get:
      tags:
      - Integrations
      operationId: getIntegrationAuthStatusV2
      summary: Check app connection status
      description: 'Whether an app is currently connected for the caller. Use this after

        sending a user through the authorization URL from

        [`GET /api/v2/integrations/auth`](#operation/getIntegrationAuthUrlV2) to

        confirm the connection completed, and before a generation that depends

        on the app.

        '
      security:
      - BearerAuth: []
      parameters:
      - name: mcp_id
        in: query
        required: true
        description: Identifier of the app to check.
        schema:
          type: string
        example: google-drive
      responses:
        '200':
          description: The connection status for this app.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntegrationAuthStatusV2Response'
              example:
                connected: false
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: No app is registered under this `mcp_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          description: The integrations service is temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /test:
    get:
      tags:
      - Health
      summary: Liveness check
      description: 'Returns a fixed greeting payload. Exists to allow clients to verify

        connectivity and credentials. Does not consult any downstream

        services.

        '
      operationId: getTest
      x-rate-limit-category: general
      responses:
        '200':
          description: API is reachable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TestResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /health:
    get:
      tags:
      - Health
      summary: Component health check
      description: 'Reports the status of downstream services. With no `category`

        parameter, returns a simple "alive" greeting. With

        `category=autogenerator` or `category=scim`, reports

        per-component status and returns 503 if any required service is

        unhealthy.

        '
      operationId: getHealth
      x-rate-limit-category: general
      parameters:
      - in: query
        name: category
        description: Component group to check. Omit for a generic liveness response.
        required: false
        schema:
          type: string
          enum:
          - autogenerator
          - scim
      responses:
        '200':
          description: All checked components healthy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/autogenerator/templates:
    get:
      tags:
      - AI Builder
      summary: List templates available to AutoGenerator
      description: 'Returns the themes/templates available to the caller''s company for

        AutoGenerator. Results are always scoped to the `auto_generator`

        feature — the scoping is applied server-side and cannot be

        overridden by the caller.


        **Pagination is opt-in.** Send `limit` (and follow `next_cursor`)

        to page; omit both `limit` and `cursor` to receive the full list

        unchanged.

        '
      operationId: listTemplates
      x-rate-limit-category: autogenerator
      parameters:
      - in: query
        name: name
        required: false
        description: Optional case-insensitive name filter.
        schema:
          type: string
      - in: query
        name: sort
        required: false
        description: Sort expression (for example `name:asc`).
        schema:
          type: string
      - in: query
        name: limit
        required: false
        description: Items per page (1–200, default 50). Enables pagination.
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
      - in: query
        name: cursor
        required: false
        description: Opaque cursor from a previous response's `next_cursor`.
        schema:
          type: string
      - in: query
        name: source
        required: false
        description: Source filter (e.g. brand vs prezent).
        schema:
          type: string
      - in: query
        name: enabledFeature
        required: false
        description: Optional feature flag filter.
        schema:
          type: string
      responses:
        '200':
          description: Templates returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThemesListResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/audiences:
    get:
      tags:
      - Audiences
      summary: List audience profiles
      description: 'Returns the audiences configured for the caller''s company.


        **Pagination is opt-in.** Send `limit` (and follow `next_cursor`)

        to page; omit both `limit` and `cursor` to receive the full list

        unchanged.

        '
      operationId: listAudiences
      x-rate-limit-category: general
      parameters:
      - in: query
        name: feature
        required: false
        description: Filter by feature scope.
        schema:
          type: string
      - in: query
        name: id
        required: false
        description: Filter to a single audience by id.
        schema:
          type: string
      - in: query
        name: sort
        required: false
        description: Sort expression (for example `name:asc`).
        schema:
          type: string
      - in: query
        name: limit
        required: false
        description: Max items per page (1–200, default 50). Sending this enables cursor pagination.
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
      - in: query
        name: cursor
        required: false
        description: Opaque cursor from a previous response's `next_cursor`.
        schema:
          type: string
      responses:
        '200':
          description: Audiences returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudiencesListResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/audiences/search:
    post:
      tags:
      - Audiences
      summary: Search audience profiles
      description: 'Free-text and field-filtered search across audience profiles. Use

        the request body''s `limit` field to cap how many matches are

        returned (most-relevant first) and the `filterBy*` fields to

        narrow the search.

        '
      operationId: searchAudiences
      x-rate-limit-category: general
      parameters:
      - in: query
        name: feature
        required: false
        description: Filter by feature scope.
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AudiencesSearchRequest'
      responses:
        '200':
          description: Matching audiences returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AudiencesListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/themes:
    get:
      tags:
      - Themes
      summary: List themes (brand templates)
      description: 'Returns the presentation themes available to the caller''s company.


        **Pagination is opt-in.** Send `limit` (and follow `next_cursor`)

        to page; omit both `limit` and `cursor` to receive the full list

        unchanged.

        '
      operationId: listThemes
      x-rate-limit-category: general
      parameters:
      - in: query
        name: name
        required: false
        description: Optional case-insensitive name filter.
        schema:
          type: string
      - in: query
        name: feature
        required: false
        description: Filter by feature scope.
        schema:
          type: string
      - in: query
        name: enabledFeature
        required: false
        description: Optional feature flag filter.
        schema:
          type: string
      - in: query
        name: sort
        required: false
        description: Sort expression (for example `name:asc`).
        schema:
          type: string
      - in: query
        name: limit
        required: false
        description: Max items per page (1–200, default 50). Sending this enables cursor pagination.
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
      - in: query
        name: cursor
        required: false
        description: Opaque cursor from a previous response's `next_cursor`.
        schema:
          type: string
      - in: query
        name: source
        required: false
        description: Source filter.
        schema:
          type: string
      responses:
        '200':
          description: Themes returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThemesListResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/file-access:
    post:
      tags:
      - File Access
      summary: Create signed access tokens for stored files
      description: 'Returns short-lived per-file access tokens that allow the caller

        to download the referenced files from the underlying storage

        backend.


        Paths that are not non-empty strings are skipped rather than

        rejected, so the response may contain fewer tokens than the number

        of `filePaths` supplied.

        '
      operationId: createAccessTokens
      x-rate-limit-category: auto_generator
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FileAccessRequest'
      responses:
        '200':
          description: Tokens minted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileAccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/preprocess:
    post:
      tags:
      - Upload
      summary: Preprocess a file in chunks
      description: 'Accepts one chunk of a multi-chunk file upload. The caller drives

        chunking via `chunkIndex` and `totalChunks`; chunks for the same

        upload share a `requestIdentifier`. Once all chunks for a

        `requestIdentifier` have arrived the file is assembled and made

        available to downstream operations.

        '
      operationId: preprocessFile
      x-rate-limit-category: general
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreprocessFileRequest'
      responses:
        '200':
          description: Chunk received.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PreprocessFileResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '415':
          $ref: '#/components/responses/UnsupportedFileType'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/validate:
    post:
      tags:
      - Upload
      summary: Validate uploaded files and/or web links
      description: 'Validates a set of previously uploaded files (referenced by

        `fileIdentifiers`) and/or a list of web links. At least one of

        `fileIdentifiers` or `webLinks` must be non-empty.

        '
      operationId: validateFiles
      x-rate-limit-category: general
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidateFilesRequest'
      responses:
        '200':
          description: Validation result returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidateFilesResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '415':
          $ref: '#/components/responses/UnsupportedFileType'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/start:
    post:
      tags:
      - Template Converter
      summary: Create a template-conversion job
      description: 'Kicks off a pipeline that applies the target brand template

        (`templateName`) to the input PowerPoint (`fileId` or

        `inputDeck`). Returns a `callback_id` to poll. Counted against

        the `TC_START` usage limit.


        Subsequent calls in the same conversion lifecycle: poll

        `GET /api/v1/template-converter/status/{callbackId}` until the

        pipeline reaches a terminal state.

        '
      operationId: createTemplateConversion
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterStartRequest'
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Job accepted; client must poll for completion.
          headers:
            Idempotency-Replayed:
              $ref: '#/components/headers/IdempotencyReplayed'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterStartResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/status/{callbackId}:
    get:
      tags:
      - Template Converter
      summary: Poll a template-conversion job
      description: 'Returns the current state of a template-conversion job. The

        response is **HTTP 200 whenever the job is found** — branch on the

        `status` field in the body, which reports whether the pipeline is

        still running, has completed, or has failed.


        For the same `callbackId`, polling after a successful conversion

        returns the same cached payload.

        '
      operationId: getTemplateConverterStatus
      x-rate-limit-category: template_converter
      parameters:
      - in: path
        name: callbackId
        required: true
        description: Callback id returned by `POST /api/v1/template-converter/start`.
        schema:
          type: string
          minLength: 1
      responses:
        '200':
          description: Current job status returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterStatusV2SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/preprocess:
    post:
      tags:
      - Template Converter
      summary: Upload a preprocessing chunk for a template-conversion input
      description: 'Accepts one chunk of a multi-chunk PPTX upload, used as the

        `inputDeck` for a subsequent template-conversion job. Only `.pptx`

        files are accepted. Chunks of the same upload are grouped by the

        body''s `requestIdentifier`, and the upload precedes the creation of

        the conversion''s `callback_id`.

        '
      operationId: createTemplateConversionPreprocessing
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreprocessFileRequest'
      responses:
        '200':
          description: Chunk received.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PreprocessFileResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '415':
          $ref: '#/components/responses/UnsupportedFileType'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/finalprocess:
    post:
      tags:
      - Template Converter
      summary: Finalise a chunked PPTX upload
      description: 'Concludes a chunked upload. `fileIdentifier` must match the

        `requestIdentifier` used when uploading the chunks via

        `POST /api/v1/template-converter/preprocess`.


        The finalised file must be a `.pptx`, no larger than 200 MB, and no

        more than 100 pages. Runs before the conversion''s `callback_id`

        exists — the `fileId` it returns is what you pass to

        `POST /api/v1/template-converter/start`.

        '
      operationId: createTemplateConversionFinalisation
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterFinalprocessRequest'
      responses:
        '200':
          description: File assembled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterFinalprocessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '415':
          $ref: '#/components/responses/UnsupportedFileType'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/{callbackId}/review-suggestions:
    get:
      tags:
      - Template Converter
      summary: Read review suggestions for a template-conversion
      description: 'Returns the colour and special-colour suggestions produced for the

        converted deck identified by `callbackId`. Each suggestion may be

        applied via the corresponding PATCH endpoint.


        The conversion must have completed and produced compliance data —

        otherwise the request is rejected.

        '
      operationId: listTemplateConversionReviewSuggestions
      x-rate-limit-category: template_converter
      parameters:
      - $ref: '#/components/parameters/CallbackIdPathCamel'
      responses:
        '200':
          description: Suggestions returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterReviewSuggestionsResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    patch:
      tags:
      - Template Converter
      summary: Update review suggestions on a template-conversion
      description: 'Applies a subset of editorial suggestions to the converted deck

        identified by `callbackId`. Kicks off a background pipeline that

        produces a new derived deck; the response carries a new

        `callback_id` to poll.

        '
      operationId: updateTemplateConversionReviewSuggestions
      x-rate-limit-category: template_converter
      parameters:
      - $ref: '#/components/parameters/CallbackIdPathCamel'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterReviewSuggestionsPatchRequest'
      responses:
        '200':
          description: Pipeline accepted; poll the returned `callback_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterAsyncProcessingResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/{callbackId}/template-change:
    post:
      tags:
      - Template Converter
      summary: Create a template change on a template-conversion
      description: 'Re-runs the conversion pipeline for an already-converted deck

        against a new target `templateName`. Returns a new `callback_id`

        to poll.

        '
      operationId: createTemplateConversionTemplateChange
      x-rate-limit-category: template_converter
      parameters:
      - $ref: '#/components/parameters/CallbackIdPathCamel'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterTemplateChangeRequest'
      responses:
        '200':
          description: Pipeline accepted; poll the returned `callback_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterAsyncProcessingResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/download/{callbackId}:
    get:
      tags:
      - Template Converter
      summary: Read the download URL for a template-conversion
      description: 'Returns a signed download URL for the converted deck identified

        by `callbackId`. Counted against the `TC_DOWNLOAD` usage limit.


        The conversion must have reached `completed` — polling

        `GET /api/v1/template-converter/status/{callbackId}` first is

        required, otherwise the request is rejected with the current

        status.

        '
      operationId: getTemplateConversionDownload
      x-rate-limit-category: template_converter
      parameters:
      - $ref: '#/components/parameters/CallbackIdPathCamel'
      responses:
        '200':
          description: Signed download URL returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterDownloadResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/reaction-feedback:
    put:
      tags:
      - Template Converter
      summary: Upsert a reaction on a template-conversion
      description: 'Records a like or qualitative feedback against a converted deck.

        The target deck is identified by `callback_id` in the request body.

        When `type` is `liked` the `value` must be a boolean; when

        `feedback` the `value` must be a string.


        This endpoint accepts **PUT** only — a POST returns

        `METHOD_NOT_ALLOWED`.

        '
      operationId: putTemplateConversionReaction
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterReactionFeedbackRequest'
      responses:
        '200':
          description: Reaction/feedback stored.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterReactionFeedbackResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/work-area-options:
    get:
      tags:
      - Template Converter
      summary: Read work-area options for a template-conversion slide
      description: 'Returns the available work-area adjustment options for the given

        slide of the given conversion job. Both parameters are supplied as

        query parameters.

        '
      operationId: listTemplateConversionWorkAreaOptions
      x-rate-limit-category: template_converter
      parameters:
      - in: query
        name: callbackId
        required: true
        description: Conversion job id. Must correspond to a live conversion session.
        schema:
          type: string
          minLength: 1
      - in: query
        name: slideIndex
        required: true
        description: Zero-based slide index.
        schema:
          type: integer
          minimum: 0
      responses:
        '200':
          description: Work-area options returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterWorkAreaOptionsResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/adjust-work-area:
    post:
      tags:
      - Template Converter
      summary: Create a work-area adjustment on a template-conversion
      description: 'Applies a selected work-area adjustment to the given slide of a

        conversion job. All parameters are supplied in the request body.


        `selection` is validated against the options currently available

        for that slide — fetch them first via

        `GET /api/v1/template-converter/work-area-options`.

        '
      operationId: createTemplateConversionWorkAreaAdjustment
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterAdjustWorkAreaRequest'
      responses:
        '200':
          description: Adjustment applied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterGenericResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/layouts:
    get:
      tags:
      - Template Converter
      summary: Read layout options for a template-conversion
      description: 'Returns the layout options available for the given slide of a

        conversion job. Both parameters are supplied as query parameters.

        '
      operationId: listTemplateConversionLayouts
      x-rate-limit-category: template_converter
      parameters:
      - in: query
        name: callbackId
        required: true
        description: Conversion job id. Must correspond to a live conversion session.
        schema:
          type: string
          minLength: 1
      - in: query
        name: slideIndex
        required: true
        description: Zero-based slide index.
        schema:
          type: integer
          minimum: 0
      responses:
        '200':
          description: Layout options returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterLayoutsResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/update-layout:
    post:
      tags:
      - Template Converter
      summary: Create a layout update on a template-conversion
      description: 'Updates the layout of one or more slides and re-renders the

        affected portion of the converted deck. Returns a new

        `callback_id` to poll. All parameters are supplied in the request

        body.

        '
      operationId: createTemplateConversionLayoutUpdate
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterUpdateLayoutRequest'
      responses:
        '200':
          description: Pipeline accepted; poll the returned `callback_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterAsyncProcessingResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/modify-format:
    post:
      tags:
      - Template Converter
      summary: Create a format modification on a template-conversion
      description: 'Applies a batch of format modifications (title-formatting,

        body-formatting) to a converted deck and re-renders the affected

        slides. Returns a new `callback_id` to poll. All parameters are

        supplied in the request body.


        The conversion must have completed before this can be called.

        '
      operationId: createTemplateConversionFormatModification
      x-rate-limit-category: template_converter
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateConverterModifyFormatRequest'
      responses:
        '200':
          description: Pipeline accepted; poll the returned `callback_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterAsyncProcessingResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/template-converter/modify-format-settings:
    get:
      tags:
      - Template Converter
      summary: Read available format-modification settings for a template-conversion
      description: 'Returns the current title/body formatting settings for **every

        slide** of a converted deck. Use these as the starting point for a

        `POST /api/v1/template-converter/modify-format` request.


        The conversion must have completed — otherwise the request is

        rejected with the current status.

        '
      operationId: getTemplateConversionFormatModificationSettings
      x-rate-limit-category: template_converter
      parameters:
      - in: query
        name: callbackId
        required: true
        description: Conversion job id. Must correspond to a completed conversion.
        schema:
          type: string
          minLength: 1
      responses:
        '200':
          description: Settings returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateConverterModifyFormatSettingsResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/webhook-subscriptions:
    post:
      tags:
      - Webhooks
      summary: Create a webhook subscription
      description: 'Registers a new HTTPS endpoint to receive signed delivery

        callbacks for the listed event types. Returns the HMAC `secret`

        ONCE — store it securely. Subsequent reads only expose the

        `secret_prefix`.

        '
      operationId: createWebhookSubscription
      x-rate-limit-category: general
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookSubscriptionCreateRequest'
      responses:
        '201':
          description: Subscription created. Body contains the `secret` — the only response that ever
            exposes it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionCreateResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    get:
      tags:
      - Webhooks
      summary: List webhook subscriptions
      description: 'Returns the subscriptions owned by the calling API key. Excludes

        soft-deleted rows. Use the standard cursor-pagination parameters

        — see [Developer Guide → Pagination](/docs/developer-guide#pagination).

        '
      operationId: listWebhookSubscriptions
      x-rate-limit-category: general
      parameters:
      - in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
          minimum: 1
          maximum: 100
          default: 25
      - in: query
        name: cursor
        required: false
        schema:
          type: string
      responses:
        '200':
          description: Paginated subscription list.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/webhook-subscriptions/{id}:
    get:
      tags:
      - Webhooks
      summary: Read a webhook subscription
      description: 'Returns one subscription. `secret_prefix` (the first 6 chars of

        the HMAC secret) is exposed for human disambiguation; the full

        secret is never returned by a read.

        '
      operationId: getWebhookSubscription
      x-rate-limit-category: general
      parameters:
      - $ref: '#/components/parameters/WebhookSubscriptionIdPath'
      responses:
        '200':
          description: Subscription found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionReadResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    patch:
      tags:
      - Webhooks
      summary: Update a webhook subscription
      description: 'Partial update. Any combination of `url`, `events`, `description`,

        or `status` may be supplied. Changes to `url` are re-validated

        against the SSRF / scheme / port rules. Setting `status` to

        `"active"` re-enables an auto-disabled subscription.

        '
      operationId: updateWebhookSubscription
      x-rate-limit-category: general
      parameters:
      - $ref: '#/components/parameters/WebhookSubscriptionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookSubscriptionUpdateRequest'
      responses:
        '200':
          description: Subscription updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionReadResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
    delete:
      tags:
      - Webhooks
      summary: Delete a webhook subscription
      description: 'Soft-deletes the subscription. The `id` is permanently retired

        — no future deliveries will be attempted, and the row is

        excluded from list responses.

        '
      operationId: deleteWebhookSubscription
      x-rate-limit-category: general
      parameters:
      - $ref: '#/components/parameters/WebhookSubscriptionIdPath'
      responses:
        '200':
          description: Subscription deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionDeleteResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/webhook-subscriptions/{id}/rotate-secret:
    post:
      tags:
      - Webhooks
      summary: Rotate the HMAC secret for a subscription
      description: 'Generates a new HMAC `secret` and invalidates the old one

        immediately. Returns the new secret ONCE — store it before

        responding to the caller. There is no grace window during which

        both secrets verify; if you need an overlap, stand up a second

        subscription on a distinct path, switch over, then delete the

        old one.

        '
      operationId: rotateWebhookSubscriptionSecret
      x-rate-limit-category: general
      parameters:
      - $ref: '#/components/parameters/WebhookSubscriptionIdPath'
      responses:
        '200':
          description: Secret rotated. Body contains the new `secret` — the only place it is ever returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionRotateResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
  /api/v1/webhook-subscriptions/{id}/test:
    post:
      tags:
      - Webhooks
      summary: Send a test delivery to a subscription
      description: 'Immediately POSTs a synthetic `webhook.test` event to the

        subscription''s URL (signed with the current secret, 5s timeout,

        no retries) and returns the response status + body verbatim.

        Use this to verify the receiver''s signature-verification path

        before real traffic flows.

        '
      operationId: testWebhookSubscription
      x-rate-limit-category: general
      parameters:
      - $ref: '#/components/parameters/WebhookSubscriptionIdPath'
      responses:
        '200':
          description: Test delivery attempted. The `delivery.ok` field indicates whether the receiver
            returned a 2xx.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionTestResponse'
        '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/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
webhooks:
  autogeneration.completed:
    post:
      tags:
      - Webhooks
      summary: AutoGenerator job completed
      description: 'Delivered when an AutoGenerator job finishes successfully. Verify

        the `X-Prezent-Signature` header and deduplicate on the event `id`.

        '
      operationId: webhookAutogenerationCompleted
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent'
      responses:
        '200':
          description: Acknowledged — return any 2xx within 10 seconds to mark the delivery successful.
  autogeneration.failed:
    post:
      tags:
      - Webhooks
      summary: AutoGenerator job failed
      description: Delivered when an AutoGenerator job fails. Same envelope, signature, and retry semantics
        as `autogeneration.completed`.
      operationId: webhookAutogenerationFailed
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent'
      responses:
        '200':
          description: Acknowledged — any 2xx within 10 seconds.
  template_conversion.completed:
    post:
      tags:
      - Webhooks
      summary: Template Converter job completed
      description: Delivered when a Template Converter job finishes successfully.
      operationId: webhookTemplateConversionCompleted
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent'
      responses:
        '200':
          description: Acknowledged — any 2xx within 10 seconds.
  template_conversion.failed:
    post:
      tags:
      - Webhooks
      summary: Template Converter job failed
      description: Delivered when a Template Converter job fails.
      operationId: webhookTemplateConversionFailed
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent'
      responses:
        '200':
          description: Acknowledged — any 2xx within 10 seconds.
  webhook.test:
    post:
      tags:
      - Webhooks
      summary: Test delivery
      description: 'Sent once when you call the subscription `test` endpoint. Single-shot

        — delivered once with no retries — so you can verify connectivity and

        signature handling before production traffic flows.

        '
      operationId: webhookTest
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent'
      responses:
        '200':
          description: Acknowledged — any 2xx within 10 seconds.
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: opaque
      description: 'Bearer token authentication. Supply the API key issued by

        Customer Success as `Authorization: Bearer <api_key>`. The API

        does NOT accept the AWS `x-api-key` header. Keys may have an

        expiry date; expired keys return `401 EXPIRED_API_KEY`. Keys are

        scoped to specific paths; calling an unauthorised path returns

        `404 ENDPOINT_NOT_FOUND`.

        '
  parameters:
    CallbackIdPath:
      name: callback_id
      in: path
      required: true
      description: Server-issued opaque identifier returned by an async kick-off endpoint. Used to poll
        status or fetch derived artefacts.
      schema:
        type: string
        minLength: 1
    CallbackIdPathCamel:
      name: callbackId
      in: path
      required: true
      description: Server-issued opaque identifier returned by an async kick-off endpoint. Used to poll
        status or fetch derived artefacts.
      schema:
        type: string
        minLength: 1
    WebhookSubscriptionIdPath:
      name: id
      in: path
      required: true
      description: The public subscription id returned by `POST /api/v1/webhook-subscriptions` — shaped
        `whsub_<32 hex chars>`.
      schema:
        type: string
        pattern: ^whsub_[a-f0-9]{32}$
        example: whsub_3f7a9b1c8d2e4f5a6b7c8d9e0f1a2b3c
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: 'Optional client-generated key (a UUID is ideal) that makes a

        write request safe to retry. The first request is processed and

        its response cached for 24 hours; an identical retry with the

        same key returns the cached response plus an

        `Idempotency-Replayed: true` header, so the job is never created

        twice. Reusing a key with a **different** body returns

        `409 IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_BODY`.

        '
      schema:
        type: string
        example: 8e6df756-18f6-4f16-8e12-7d7a5c5cb181
  headers:
    IdempotencyReplayed:
      description: Present and set to `true` when this response was served from the idempotency cache
        for a repeated `Idempotency-Key`.
      schema:
        type: string
        enum:
        - 'true'
    XRateLimitLimit:
      description: 'The configured request limit for the rate-limit category

        (requests per 60-second window) that applied to this call.

        The applicable category is the operation''s `x-rate-limit-category`.

        Returned on every response (success and 429) so clients can

        self-throttle. See the Rate limits guide for the default

        per-category numbers.

        '
      schema:
        type: integer
        format: int32
        minimum: 0
    XRateLimitRemaining:
      description: 'Approximate number of requests remaining in the current

        60-second window for this caller and category.

        '
      schema:
        type: integer
        format: int32
        minimum: 0
    XRateLimitReset:
      description: Unix timestamp (seconds) when the current rate-limit window resets.
      schema:
        type: integer
        format: int64
        minimum: 0
    RetryAfter:
      description: Number of seconds the client should wait before retrying.
      schema:
        type: integer
        format: int32
        minimum: 0
  schemas:
    SuccessEnvelope:
      type: object
      description: 'Standard success envelope. Endpoint-specific schemas extend this

        and constrain the `data` property to their concrete shape.

        Additional legacy keys (`status`, `log`, …) may appear alongside

        `success`/`data` for backwards compatibility, and some legacy

        handlers omit `success`, so it is not marked required.

        '
      required:
      - data
      properties:
        success:
          type: boolean
          description: '`true` on success (omitted by some legacy handlers).'
        data:
          type: object
          description: Endpoint-specific payload.
      additionalProperties: true
    ErrorEnvelope:
      type: object
      description: 'Standard error envelope returned by every documented endpoint

        (both in-Lambda and gateway-level errors). Additional legacy

        keys may appear alongside `success`/`data`/`error` for

        backwards compatibility.

        '
      required:
      - success
      - data
      - error
      properties:
        success:
          type: boolean
          const: false
          description: Always `false` on error.
        data:
          type:
          - object
          - 'null'
          description: Always `null` on error.
        error:
          type: object
          required:
          - code
          - message
          description: Error description.
          properties:
            code:
              $ref: '#/components/schemas/ErrorCode'
            message:
              type: string
              description: Human-readable error description (English).
            details:
              type: object
              description: Optional structured details (validation failures, downstream-service info,
                etc.).
              additionalProperties: true
      additionalProperties: true
    ErrorCode:
      type: string
      description: 'Stable identifier for an error condition. Codes never change

        meaning or HTTP status once published.

        '
      enum:
      - INVALID_API_KEY
      - EXPIRED_API_KEY
      - UNAUTHORIZED
      - FORBIDDEN
      - ENDPOINT_NOT_FOUND
      - RESOURCE_NOT_FOUND
      - NOT_FOUND
      - METHOD_NOT_ALLOWED
      - UNSUPPORTED_FILE_TYPE
      - INVALID_INPUT
      - UNPROCESSABLE_ENTITY
      - RATE_LIMIT_EXCEEDED
      - USAGE_LIMIT_EXCEEDED
      - TOO_MANY_REQUESTS
      - THROTTLED
      - BAD_REQUEST
      - INVALID_JSON
      - MISSING_REQUIRED_FIELD
      - MISSING_QUERY_PARAM
      - MISSING_CALLBACK_ID
      - MISSING_SLIDES_ARRAY
      - MISSING_PROMPT
      - MISSING_TEMPLATE_ID
      - MISSING_FILE_CONTENT
      - MISSING_SHARE_DETAILS
      - INVALID_TYPE
      - INVALID_DATA
      - INVALID_DATA_TYPE
      - INVALID_PAYLOAD
      - INVALID_REQUEST
      - API_REQUEST_FAILED
      - FILE_UPLOAD_FAILED
      - MAX_RETRIES_EXCEEDED
      - EXTERNAL_SERVICE_ERROR
      - INTERNAL_SERVER_ERROR
      - SERVICE_UNAVAILABLE
      - GATEWAY_TIMEOUT
    CallbackEnvelope:
      type: object
      description: 'Async-start envelope for `POST /api/v1/autogenerator`.


        This endpoint does **not** use the canonical `success`/`data`

        envelope. The payload is returned under `resData`, alongside

        top-level `message` and `error` keys.

        '
      required:
      - resData
      properties:
        message:
          type: string
          description: Human-readable status, for example "Job submitted successfully".
        resData:
          type: object
          required:
          - callback_id
          properties:
            callback_id:
              type: string
              description: Server-issued opaque identifier to poll.
            token:
              type: string
              description: One-time token issued alongside the `callback_id`, used by callback-id-scoped
                URLs.
          additionalProperties: true
        error:
          type: string
          nullable: true
          description: Null on success; an error string otherwise.
      additionalProperties: true
    RateLimitInfo:
      type: object
      description: Out-of-body rate-limit information. Returned via headers, not in the response body;
        this schema exists for tooling only.
      properties:
        limit:
          type: integer
          description: Configured requests-per-window for the category.
        remaining:
          type: integer
          description: Approximate requests remaining in the current window.
        reset:
          type: integer
          format: int64
          description: Unix timestamp (seconds) when the window resets.
        retry_after_seconds:
          type: integer
          description: Seconds to wait before retrying.
    TestResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            properties:
              message:
                type: string
                description: Fixed greeting string.
            additionalProperties: true
    HealthResponse:
      description: Liveness / health response. The simple liveness probe returns just a `message`; component
        health checks may return a richer `data` payload (per-service status, timestamp).
      type: object
      additionalProperties: true
      properties:
        message:
          type: string
          description: Liveness message.
        status:
          type: string
          description: Overall status, when reported.
        data:
          type: object
          additionalProperties: true
          description: Optional richer health payload.
          properties:
            message:
              type: string
            category:
              type: string
              description: The category that was checked.
            services:
              type: array
              description: Per-component status report.
              items:
                type: object
                additionalProperties: true
                properties:
                  name:
                    type: string
                  status:
                    type: string
                  detail:
                    type: string
            timestamp:
              type: string
              format: date-time
    AutoGeneratorStartRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator`.
      required:
      - prompt
      properties:
        prompt:
          type: string
          description: Natural-language description of the deck to generate.
        texts:
          type: array
          description: Additional free-text context to ground the deck.
          items:
            type: string
        files:
          type: array
          description: Previously uploaded supporting files (by id).
          items:
            type: string
        web_links:
          type: array
          description: Web URLs to ingest as additional context.
          items:
            type: string
            format: uri
        audience:
          type: object
          description: Target audience. Must be an object — `id` and `num_id` are required when `audience`
            is provided.
          required:
          - id
          - num_id
          properties:
            id:
              type: string
              minLength: 1
              description: Audience id.
            num_id:
              type: integer
              description: Numeric audience id.
            audienceId:
              type: string
            fullName:
              type: string
            type:
              type: string
            ownerID:
              type: string
              nullable: true
            fingerPrint:
              type: string
            isActive:
              type: boolean
            isPrivate:
              type: boolean
            isShared:
              type: boolean
            shared:
              type: boolean
            fingerprintResponse:
              type: array
              items:
                type: object
                additionalProperties: true
          additionalProperties: true
          example:
            id: aud_9f1b2c2f
            num_id: 42
            fullName: Executive Leadership
            type: standard
        template_id:
          type: string
          description: Target theme/template id.
        settings:
          type: object
          description: Optional per-generation settings. Every key is optional; omit the object entirely
            to use the defaults configured for the API key.
          properties:
            template_id:
              type: string
              minLength: 1
              description: Template id to generate against. Used only when the root-level `template_id`
                is not provided; if both are sent, the root-level value wins and this one is ignored.
            ai_model:
              type: string
              description: Generation model to use.
              enum:
              - astrid_standard
              - astrid_advanced
              example: astrid_standard
            image_preferences:
              type: array
              description: Image libraries to source imagery from. Cannot be an empty array when provided.
              minItems: 1
              items:
                type: string
                enum:
                - prezent_library
                - company_library
                - brand_library
              example:
              - prezent_library
              - company_library
            knowledge_base:
              type: string
              description: Which context sources the generator may draw on.
              enum:
              - uploaded_only
              - uploaded_and_web
              example: uploaded_and_web
            data_sources:
              type: array
              description: Where to render source attributions.
              items:
                type: string
                enum:
                - add_sources_to_footer
                - add_sources_to_slides_note
              example:
              - add_sources_to_footer
              - add_sources_to_slides_note
            speaker_notes:
              type: array
              description: Speaker-notes generation options.
              items:
                type: string
                enum:
                - add_speaker_notes
                - add_speaker_notes_to_slides_note
              example:
              - add_speaker_notes
              - add_speaker_notes_to_slides_note
            preserve_text:
              type: boolean
              description: Preserve the supplied text verbatim instead of rewriting it.
            voice_settings:
              type: object
              description: Brand-voice configuration.
              required:
              - type
              properties:
                type:
                  type: string
                  description: Voice profile to apply.
                  enum:
                  - brand
                  - standard
                  - custom
                  example: standard
                details:
                  type: object
                  description: Required when `type` is `custom`.
                  required:
                  - tone
                  - emotion
                  properties:
                    tone:
                      type: string
                      minLength: 1
                    emotion:
                      type: string
                      minLength: 1
          additionalProperties: true
          example:
            template_id: 8f14e45f-ceea-467a-9f1b-2c2f0e3a1b90
            ai_model: astrid_standard
            image_preferences:
            - prezent_library
            - company_library
            knowledge_base: uploaded_and_web
            data_sources:
            - add_sources_to_footer
            - add_sources_to_slides_note
            speaker_notes:
            - add_speaker_notes
            - add_speaker_notes_to_slides_note
      additionalProperties: true
    AutoGeneratorStatusBulkRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/status-bulk`.
      required:
      - callback_ids
      properties:
        callback_ids:
          type: array
          description: Callback ids to look up.
          minItems: 1
          items:
            type: string
      additionalProperties: true
    AutoGeneratorMetaRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/meta`.
      required:
      - assetIds
      - callbackID
      properties:
        assetIds:
          type: array
          description: Asset ids to look up metadata for.
          minItems: 1
          items:
            type: string
        callbackID:
          type: string
          description: Parent deck callback id. (Legacy camelCase preserved for backwards compatibility;
            new clients should also continue to send this field.)
      additionalProperties: true
    AutoGeneratorDownloadRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/download`.
      required:
      - callback_id
      properties:
        callback_id:
          type: string
          minLength: 1
          description: Deck callback id to merge & download.
        sources:
          type: object
          description: Source-attribution configuration for the merged output.
          properties:
            add_sources_to_slides_note:
              type: boolean
              description: Render source attributions in slide notes.
          additionalProperties: true
        speaker_notes:
          type: object
          description: Speaker-notes configuration for the merged output.
          properties:
            add_speaker_notes_to_slides_note:
              type: boolean
              description: Merge speaker notes into slide notes.
            speaker_notes_type:
              type: string
              description: Speaker-notes formatting style.
          additionalProperties: true
      additionalProperties: true
    AutoGeneratorRegenerateRequest:
      type: object
      description: 'Request body for `POST /api/v1/autogenerator/regenerate`.


        `callback_id` is always required. Which of the remaining fields are

        required depends on the `operation` query parameter:


        | `operation` | Additionally required |

        |---|---|

        | `audience_change` | `audience` |

        | `template_change` | `template_code` |

        | `slide_change` | `slide_override` |

        | `context_change` | `context` and `slide_override` |

        | `smart_chart_change` | `slide_override` (with `workflow` and `slide_type`) |

        | `node_change` | `slide_override` |

        | `story_content_change` | `story_content_override` |

        | `add_slide` | `context` (with `context.context` prompt) and `slide_position` |

        | `duration_change` | `duration` (with `duration.no_of_slides`) |

        '
      required:
      - callback_id
      properties:
        callback_id:
          type: string
          minLength: 1
          description: Existing deck callback id. Must be a non-empty string.
        audience:
          type: object
          description: Override audience for the regenerated portion. Required for `audience_change`.
            When omitted, the audience is resolved automatically from the original deck.
          required:
          - id
          - num_id
          properties:
            id:
              type: string
              minLength: 1
            num_id:
              type: integer
          additionalProperties: true
        template_code:
          type: string
          minLength: 1
          description: Override template code. Required for `template_change`.
        slide_override:
          type: object
          description: 'Slide-level overrides. Required for `slide_change`,

            `context_change`, `smart_chart_change`, and `node_change`.


            For `smart_chart_change`, `workflow` (string) and `slide_type`

            (string) are both required. For `node_change`, pass the target

            slide as `unique_id` (or `slide`).

            '
          additionalProperties: true
        story_content_override:
          type: object
          description: Narrative-content overrides. Required for `story_content_change`. May also be supplied
            as an array.
          additionalProperties: true
        context:
          type: object
          description: Additional context to inject into the regenerate pass. Required for `context_change`
            and `add_slide`; for `add_slide`, the nested `context` property carries the prompt and must
            be a non-empty string.
          properties:
            context:
              type: string
              minLength: 1
              description: Prompt text. Required for `add_slide`.
          additionalProperties: true
        slide_position:
          type: integer
          minimum: 0
          description: Zero-based position at which to insert the new slide. Required for `add_slide`.
        duration:
          type: object
          description: Desired length of the regenerated deck. Required for `duration_change`.
          required:
          - no_of_slides
          properties:
            no_of_slides:
              type: integer
              minimum: 1
              description: Target slide count. Must be a positive number.
          additionalProperties: true
        voice_settings:
          type: object
          description: Voice/tone settings.
          additionalProperties: true
        data_sources_settings:
          type: object
          description: Source-attribution configuration. Defaults to both flags `false` when omitted.
          properties:
            add_sources_to_footer:
              type: boolean
            add_sources_to_slides_note:
              type: boolean
          additionalProperties: true
        preserve_text:
          type: boolean
          description: Preserve existing text where possible. When omitted, the behaviour is inherited
            from the original deck's workflow.
      additionalProperties: true
    AutoGeneratorNodeChangeRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/node-change`.
      required:
      - callback_id
      - slide_callback_id
      properties:
        callback_id:
          type: string
          minLength: 1
          description: Deck callback id.
        slide_callback_id:
          type: string
          minLength: 1
          description: Slide callback id to modify. The node count applied is read from the slide's own
            state, not from the request.
      additionalProperties: true
    AutoGeneratorSlideDataRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/slide-data`.
      required:
      - slide_callback_id
      properties:
        slide_callback_id:
          type: string
          description: Slide callback id whose data to return.
      additionalProperties: true
    AutoGeneratorExtractImagesRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/extract-images`.
      required:
      - s3_bucket
      - s3_path
      properties:
        s3_bucket:
          type: string
          description: S3 bucket containing the PowerPoint.
        s3_path:
          type: string
          description: S3 key (path) of the PowerPoint.
      additionalProperties: true
    AutoGeneratorBrandImageSearchRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/brand-image-search`.
      required:
      - callback_id
      properties:
        callback_id:
          type: string
          description: Deck callback id (used for scoping to the right company).
        query:
          type: string
          description: Search query. Defaults to `*` (return all).
        skip:
          type: integer
          minimum: 0
          description: Number of results to skip (pagination offset).
        limit:
          type: integer
          minimum: 1
          maximum: 100
          description: Maximum number of results to return.
      additionalProperties: true
    AutoGeneratorLibraryImageSearchRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/library-image-search`.
      properties:
        searchKey:
          type: string
          description: Search query. If blank, derived from the supplied slide context.
        limit:
          type: integer
          default: 30
          description: Maximum number of results.
        offset:
          type: integer
          default: 0
          description: Result offset.
        slide_callback_id:
          type: string
          description: Optional slide callback id used to infer `searchKey`.
      additionalProperties: true
    AutoGeneratorReplaceImageRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/replace-image`.
      required:
      - oldImage
      - newImage
      - slide_callback_id
      properties:
        oldImage:
          type: object
          description: Description of the existing image being replaced.
          required:
          - meta
          - shapeType
          properties:
            meta:
              type: object
              description: Image metadata (size, position, etc.).
              additionalProperties: true
            shapeType:
              type: string
              description: PowerPoint shape type.
          additionalProperties: true
        newImage:
          type: object
          description: 'Description of the replacement image. `imageIndex` and `source`

            are always required; the remaining fields depend on `source`:


            | `source` | Additionally required |

            |---|---|

            | `myWorkspace` | `s3_path`, `s3_bucket` |

            | `s3` | `s3_path`, `s3_bucket` |

            | `brand-images` | `s3_path` |

            | `extracted` | `s3_path` (bucket is resolved server-side) |

            | `adobe` | `id` |

            | `freepik` | `id` |

            | `upload` | `image`, `extension` |

            '
          required:
          - imageIndex
          - source
          properties:
            imageIndex:
              type: integer
              description: Index of the image to replace on the slide.
            source:
              type: string
              enum:
              - myWorkspace
              - adobe
              - freepik
              - upload
              - extracted
              - s3
              - brand-images
              description: Source of the replacement image.
            s3_path:
              type: string
              description: S3 key when `source` is `myWorkspace`, `s3`, `brand-images`, or `extracted`.
            s3_bucket:
              type: string
              description: S3 bucket when `source` is `myWorkspace` or `s3`.
            id:
              type: string
              description: Image id when `source` is `adobe` or `freepik`.
            image:
              type: string
              description: Base64-encoded image content when `source` is `upload`.
            extension:
              type: string
              description: File extension (e.g. `png`, `jpg`) when `source` is `upload`.
          additionalProperties: true
        slide_callback_id:
          type: string
          minLength: 1
          description: Slide callback id where the image lives. The slide's S3 bucket and path are resolved
            from this id.
        duplicate_slide_callback_id:
          type: string
          description: Optional duplicate slide id to mirror the replacement onto.
      additionalProperties: true
    AutoGeneratorReactionFeedbackRequest:
      type: object
      description: Request body for `POST /api/v1/autogenerator/reaction-feedback`.
      required:
      - uuid
      - type
      - value
      properties:
        uuid:
          type: string
          format: uuid
          description: Target asset uuid (deck or slide). Must be a canonical UUID — `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`.
        type:
          type: string
          enum:
          - liked
          - feedback
          description: Reaction kind.
        value:
          description: When `type=liked`, a boolean. When `type=feedback`, a non-empty string.
          oneOf:
          - type: boolean
          - type: string
        shareDetails:
          type: object
          description: Additional details. **Required** when `type=feedback`.
          additionalProperties: true
      additionalProperties: true
    AutoGeneratorSlideActionsRequest:
      type: object
      description: 'Request body for `POST /api/v1/autogenerator/slide-actions`.


        `action` is always required. The remaining fields differ per action

        — note that the two note-style actions do **not** take the same

        shape:


        | `action` | Additionally required |

        |---|---|

        | `duplicate` | `deck_callback_id`, `slide_callback_id` |

        | `delete` | `deck_callback_id`, `slide_callback_id` |

        | `add_sources_to_slides_note` | `data.uuid`, `data.addDataSourcesTo.slideNote` |

        | `speaker_notes` | `uuid`, `type`, `data` |

        '
      required:
      - action
      properties:
        action:
          type: string
          enum:
          - duplicate
          - delete
          - add_sources_to_slides_note
          - speaker_notes
          description: Sub-action to perform.
        deck_callback_id:
          type: string
          minLength: 1
          description: Deck callback id. Required for `duplicate` and `delete`.
        slide_callback_id:
          type: string
          minLength: 1
          description: Slide callback id. Required for `duplicate` and `delete`.
        uuid:
          type: string
          minLength: 1
          description: Target deck callback id. Required for `speaker_notes` only — `add_sources_to_slides_note`
            carries its id at `data.uuid` instead.
        type:
          type: string
          description: Note sub-type. Required for `speaker_notes` only.
        data:
          type: object
          description: 'Action-specific payload. Required for

            `add_sources_to_slides_note` and `speaker_notes`.


            For `add_sources_to_slides_note` it must contain `uuid` (the

            deck callback id) and `addDataSourcesTo.slideNote` (boolean).

            '
          properties:
            uuid:
              type: string
              minLength: 1
              description: Deck callback id. Required for `add_sources_to_slides_note`.
            addDataSourcesTo:
              type: object
              description: Required for `add_sources_to_slides_note`.
              required:
              - slideNote
              properties:
                slideNote:
                  type: boolean
                  description: Whether to write source attributions into the slide notes.
              additionalProperties: true
          additionalProperties: true
      additionalProperties: true
    AutoGeneratorStartResponse:
      description: Response body for `POST /api/v1/autogenerator`.
      allOf:
      - $ref: '#/components/schemas/CallbackEnvelope'
    AutoGeneratorStatusResponse:
      description: 'Response body for `GET /api/v1/autogenerator/status`.


        This endpoint does **not** use the canonical `success`/`data`

        envelope — the fields below are returned at the **top level** of

        the response body, not nested under `data`.

        '
      allOf:
      - $ref: '#/components/schemas/AutoGeneratorStatusData'
    AutoGeneratorStatusData:
      type: object
      description: 'AutoGenerator job state. The handler emits further legacy fields

        alongside the documented ones; only the documented fields are part

        of the contract.


        Note the response does **not** echo back the `callback_id` you

        polled with.

        '
      properties:
        message:
          type: string
          description: Human-readable status, for example "Workflow status polling completed."
        status:
          type: string
          enum:
          - in_progress
          - success
          - failed
          description: Job status.
        prompt:
          type: string
          description: Original prompt that initiated the job.
        fileName:
          type: string
          description: Filename of the generated deck.
        allSlides:
          type: array
          description: Generated slides (present once `status=success`).
          items:
            type: object
            additionalProperties: true
        extracted_images:
          type: array
          description: Images extracted from supporting files.
          items:
            type: object
            additionalProperties: true
        company:
          type: string
          description: Owning company id.
        companyDisplayName:
          type: string
          description: Owning company display name.
        final_output:
          type: object
          description: Final-output blob (present once `status=success`).
          additionalProperties: true
        template_code:
          type: string
          description: Target template code used for generation.
        audience:
          type: string
          description: Target audience used for generation.
        execution_start:
          type: string
          format: date-time
          description: Pipeline start time.
        execution_end:
          type: string
          format: date-time
          description: Pipeline end time (present once terminal).
        presentation_theme:
          type: object
          description: Resolved theme metadata.
          additionalProperties: true
        voice_settings:
          type: object
          description: Voice/tone settings applied.
          additionalProperties: true
        speaker_notes:
          type: object
          description: Speaker-notes configuration applied.
          additionalProperties: true
        cached:
          type: boolean
          description: Whether this response was served from cache.
        cached_at:
          type: string
          format: date-time
          description: Timestamp of the cached entry.
      additionalProperties: true
    AutoGeneratorStatusBulkResponse:
      description: Response body for `POST /api/v1/autogenerator/status-bulk`. Standalone schema — unlike
        most responses, `data` is an array, so this does not extend SuccessEnvelope (whose `data` is an
        object).
      type: object
      required:
      - success
      - data
      additionalProperties: true
      properties:
        success:
          type: boolean
          const: true
          description: Always `true` on success.
        data:
          type: array
          description: One entry per requested callback id.
          items:
            type: object
            additionalProperties: true
            properties:
              slide_id:
                type: string
                description: Slide id within the deck.
              layouts:
                type: array
                description: Layouts available for this slide.
                items:
                  type: object
                  additionalProperties: true
    AutoGeneratorMetaResponse:
      description: Response body for `POST /api/v1/autogenerator/meta`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            description: Metadata payload from the SlideMeta service (passthrough).
            additionalProperties: true
    AutoGeneratorDownloadResponse:
      type: object
      description: 'Response body for `POST /api/v1/autogenerator/download`.


        This endpoint does **not** use the canonical `success`/`data`

        envelope — the fields below are returned at the **top level** of

        the response body.

        '
      required:
      - download_url
      properties:
        message:
          type: string
          description: Human-readable confirmation, for example "Slides merged successfully".
        status:
          type: string
          enum:
          - success
          description: Merge status.
        output_file:
          type: string
          description: Filename of the merged file.
        download_url:
          type: string
          format: uri
          description: Signed download URL.
      additionalProperties: true
    AutoGeneratorRegenerateResponse:
      description: Response body for `POST /api/v1/autogenerator/regenerate`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - new_callback_id
            properties:
              new_callback_id:
                type: string
                description: Callback id to poll for the regenerate sub-job.
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    AutoGeneratorGenericDataResponse:
      description: Generic success envelope where `data` is an opaque object passed through from a downstream
        service. Used by node-change, slide-data, extract-images.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            description: Downstream payload (shape varies).
            additionalProperties: true
    AutoGeneratorMessageDataResponse:
      description: Success envelope with a human-readable `message` alongside `data`. Used by image-search
        and replace-image.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            description: Service-specific payload.
            additionalProperties: true
    AutoGeneratorReactionFeedbackResponse:
      description: Response body for `POST /api/v1/autogenerator/reaction-feedback`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            properties:
              uuid:
                type: string
                description: Target asset uuid.
              type:
                type: string
                enum:
                - liked
                - feedback
                description: Reaction kind.
              value:
                description: Recorded value.
                oneOf:
                - type: boolean
                - type: string
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    AutoGeneratorSlideActionsResponse:
      description: "Response body for `POST /api/v1/autogenerator/slide-actions`.\nThe `data` shape depends\
        \ on the requested `action`:\n  - `duplicate` → `{ new_callback_id }`.\n  - `delete` → `{ deleted_slide_id\
        \ }`.\n  - `add_sources_to_slides_note` / `speaker_notes` → service\n    payload.\n"
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            properties:
              new_callback_id:
                type: string
                description: Returned for `action=duplicate`.
              deleted_slide_id:
                type: string
                description: Returned for `action=delete`.
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    AudiencesSearchRequest:
      type: object
      description: Request body for `POST /api/v1/audiences/search`.
      properties:
        query:
          type: string
          description: Free-text search query.
        id:
          type: string
          description: Filter to a single audience by id.
        sort:
          type: string
          description: Sort expression (for example `name:asc`).
        filterBy:
          type: object
          description: Field-level filter.
          additionalProperties: true
        filterByCollection:
          type: object
          description: Collection-level filter.
          additionalProperties: true
        fields:
          type: array
          description: Subset of fields to return.
          items:
            type: string
        extraFields:
          type: array
          description: Additional fields to include beyond defaults.
          items:
            type: string
        limit:
          type: integer
          default: 15
          description: Maximum number of results.
      additionalProperties: true
    AudiencesListResponse:
      description: Response body for `GET /api/v1/audiences` and `POST /api/v1/audiences/search`. `result`
        and `items` are the same array of audience profiles (`items` is the pagination alias).
      type: object
      additionalProperties: true
      required:
      - result
      properties:
        success:
          type: boolean
          description: Always `true` on success.
        result:
          type: array
          description: Audience profiles.
          items:
            type: object
            additionalProperties: true
            properties:
              id:
                type: string
                description: Audience identifier.
              name:
                type: string
                description: Audience name.
        items:
          type: array
          description: Same audience profiles as `result` (present when paginating).
          items:
            type: object
            additionalProperties: true
        next_cursor:
          type:
          - string
          - 'null'
          description: Opaque cursor for the next page, or `null` on the last page. Pagination is opt-in
            — omit `limit`/`cursor` to receive the full list.
    ThemesListResponse:
      description: Response body for `GET /api/v1/themes` and the templates endpoints under autogenerator/template-converter.
        `data` is the array of themes/templates; `next_cursor` is a sibling field.
      type: object
      additionalProperties: true
      required:
      - data
      properties:
        success:
          type: boolean
          description: Always `true` on success.
        data:
          type: array
          description: Themes / templates.
          items:
            type: object
            additionalProperties: true
            properties:
              id:
                type: string
                description: Theme identifier.
              name:
                type: string
                description: Theme display name.
              code:
                type: string
                description: Internal theme code.
              source:
                type: string
                description: Origin (e.g. brand, prezent).
        next_cursor:
          type:
          - string
          - 'null'
          description: Opaque cursor for the next page, or `null` on the last page. Pagination is opt-in
            — omit `limit`/`cursor` to receive the full list.
    FileAccessRequest:
      type: object
      description: Request body for `POST /api/v1/file-access`.
      required:
      - filePaths
      properties:
        filePaths:
          type: array
          description: List of stored file paths to mint tokens for.
          minItems: 1
          items:
            type: string
        source:
          type: string
          enum:
          - betaimages
          - magikarp
          description: Storage backend source.
      additionalProperties: true
    FileAccessResponse:
      description: Response body for `POST /api/v1/file-access`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - access_tokens
            properties:
              access_tokens:
                type: object
                description: Map of `filePath` → signed access token.
                additionalProperties:
                  type: string
                  description: Signed access token for the corresponding file path.
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    PreprocessFileRequest:
      type: object
      description: Request body for `POST /api/v1/preprocess` and `POST /api/v1/template-converter/preprocess`.
      required:
      - fileContent
      - fileName
      - chunkIndex
      - totalChunks
      - requestIdentifier
      properties:
        fileContent:
          type: string
          description: Chunk content as base64 / `data:` URL.
        fileName:
          type: string
          description: Original filename including extension.
        chunkIndex:
          type: integer
          minimum: 0
          description: Zero-based index of this chunk.
        totalChunks:
          type: integer
          minimum: 1
          description: Total number of chunks for this upload.
        requestIdentifier:
          type: string
          description: Caller-supplied identifier that groups chunks of the same upload.
      additionalProperties: true
    PreprocessFileResponse:
      description: Response body for `POST /api/v1/preprocess` and `POST /api/v1/template-converter/preprocess`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - request_identifier
            - file_name
            properties:
              request_identifier:
                type: string
                description: The caller-supplied identifier.
              file_name:
                type: string
                description: The filename that was processed.
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    ValidateFilesRequest:
      type: object
      description: 'Request body for `POST /api/v1/validate`. At least one of

        `fileIdentifiers` or `webLinks` must be non-empty.

        '
      properties:
        fileIdentifiers:
          type: object
          description: Map of `uuid` → `fileName` for previously uploaded files.
          additionalProperties:
            type: string
            description: Original filename for that uuid.
        webLinks:
          type: array
          description: List of URLs to validate.
          items:
            type: string
            format: uri
      additionalProperties: true
    ValidateFilesResponse:
      description: Response body for `POST /api/v1/validate`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            properties:
              files:
                type: array
                description: Per-file validation results.
                items:
                  type: object
                  properties:
                    uuid:
                      type: string
                      description: File uuid.
                    file_name:
                      type: string
                      description: Original filename.
                    valid:
                      type: boolean
                      description: Whether the file passed validation.
                    reason:
                      type: string
                      description: Failure reason when `valid=false`.
                  additionalProperties: true
              web_links:
                type: array
                description: Per-link validation results.
                items:
                  type: object
                  properties:
                    url:
                      type: string
                      description: The link.
                    valid:
                      type: boolean
                      description: Whether the link is reachable and ingestable.
                    reason:
                      type: string
                      description: Failure reason when `valid=false`.
                  additionalProperties: true
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    TemplateConverterStartRequest:
      type: object
      description: 'Request body for `POST /api/v1/template-converter/start`.


        Supply the input deck **either** as `fileId` (a previously uploaded

        file, whose details are resolved server-side) **or** as an inline

        `inputDeck` object. `fileId` takes precedence when both are sent.


        Every optional setting below falls back to the defaults configured

        for the API key, and then to the documented default.

        '
      required:
      - templateName
      properties:
        fileId:
          type: string
          description: Identifier of a previously uploaded input deck. Supply either `fileId` or `inputDeck`.
        inputDeck:
          type: object
          description: Inline reference to the input deck. All four properties below are required when
            `inputDeck` is used.
          required:
          - numOfPages
          - s3Bucket
          - s3Prefix
          - sizeKb
          properties:
            numOfPages:
              type: integer
              description: Number of slides in the input deck. Also used for the projected usage-limit
                check.
            s3Bucket:
              type: string
              minLength: 1
              description: S3 bucket holding the input deck.
            s3Prefix:
              type: string
              minLength: 1
              description: S3 key (prefix) of the input deck.
            sizeKb:
              type: number
              description: Size of the input deck in kilobytes.
            presentationName:
              type: string
              description: Display name for the converted deck.
          additionalProperties: true
        templateName:
          type: string
          minLength: 1
          description: Code of the target brand template. Must be one the caller's company is authorised
            to use — an unknown or unauthorised code is rejected.
        includeImageWithoutData:
          type: boolean
          default: false
          description: Carry over images that have no associated data.
        includeImageWithData:
          type: boolean
          default: false
          description: Carry over images that have associated data.
        includeIcons:
          type: boolean
          default: false
          description: Carry over icons.
        includeSpecialColor:
          type: boolean
          default: false
          description: Preserve special color treatments from the source deck.
        color_preference:
          type: string
          enum:
          - standard
          - advanced
          default: standard
          description: Color treatment preference. Also accepted as `colorPreference`.
        content_formatting_preference:
          type: string
          enum:
          - standard
          - advanced
          description: Content-formatting preference. Also accepted as `contentFormattingPreference`.
        modifyFormat:
          type: string
          enum:
          - source
          - target
          description: Which deck's formatting to apply. Also accepted as `modify_format`.
        settings:
          type: object
          description: Per-conversion settings. Each key overrides the corresponding API-key default.
          properties:
            ai_mode:
              type: string
              enum:
              - standard
              - thinking
              default: standard
              description: Conversion AI mode.
            work_area_option:
              type: string
              enum:
              - no-adjust
              - auto-adjust
              - scale-to-fit
              - auto-adjust-la
              default: no-adjust
              description: Work-area adjustment behaviour.
            modifyFormat:
              type: string
              enum:
              - source
              - target
              description: Which deck's formatting to apply. Also accepted as `settings.modify_format`.
            color_preference:
              type: string
              enum:
              - standard
              - advanced
              default: standard
              description: Color treatment preference.
          additionalProperties: true
      additionalProperties: true
    TemplateConverterFinalprocessRequest:
      type: object
      description: Request body for `POST /api/v1/template-converter/finalprocess`.
      required:
      - fileIdentifier
      - fileName
      properties:
        fileIdentifier:
          type: string
          description: Identifier shared across all chunks of this upload. Must match the `requestIdentifier`
            sent with each chunk.
        fileName:
          type: string
          description: Final filename. Must end in `.pptx`.
      additionalProperties: true
    TemplateConverterReviewSuggestionsPatchRequest:
      type: object
      description: 'Request body for

        `PATCH /api/v1/template-converter/{callbackId}/review-suggestions`.


        **At least one** of `colorSuggestions` or `specialColorSuggestions`

        must be present. Whichever you send must carry `status: "edited"`

        and a `values` object containing both `currentColor` and

        `newColor`.

        '
      anyOf:
      - required:
        - colorSuggestions
      - required:
        - specialColorSuggestions
      properties:
        colorSuggestions:
          type: object
          description: Colour replacement to apply.
          required:
          - status
          - values
          properties:
            status:
              type: string
              enum:
              - edited
              description: Must be `edited`. Any other value is rejected.
            values:
              type: object
              required:
              - currentColor
              - newColor
              properties:
                currentColor:
                  type: string
                  description: The colour being replaced.
                newColor:
                  type: string
                  description: The replacement colour.
              additionalProperties: true
          additionalProperties: true
        specialColorSuggestions:
          type: object
          description: Special-colour replacement to apply.
          required:
          - status
          - values
          properties:
            status:
              type: string
              enum:
              - edited
              description: Must be `edited`. Any other value is rejected.
            values:
              type: object
              required:
              - currentColor
              - newColor
              properties:
                currentColor:
                  type: string
                  description: The colour being replaced.
                newColor:
                  type: string
                  description: The replacement colour.
              additionalProperties: true
          additionalProperties: true
      additionalProperties: true
    TemplateConverterTemplateChangeRequest:
      type: object
      description: Request body for `POST /api/v1/template-converter/{callbackId}/template-change`.
      required:
      - templateName
      properties:
        templateName:
          type: string
          minLength: 1
          description: Code of the new target brand template. Must be one the caller's company is authorised
            to use — an unknown or unauthorised code is rejected.
      additionalProperties: true
    TemplateConverterReactionFeedbackRequest:
      type: object
      description: Request body for `PUT /api/v1/template-converter/reaction-feedback`.
      required:
      - callback_id
      - type
      - value
      properties:
        callback_id:
          type: string
          minLength: 1
          description: Converted-deck callback id. Must correspond to a live conversion session.
        type:
          type: string
          enum:
          - liked
          - feedback
          description: Reaction kind.
        value:
          description: When `type=liked`, a boolean. When `type=feedback`, a string. An empty string is
            rejected.
          oneOf:
          - type: boolean
          - type: string
      additionalProperties: true
    TemplateConverterAdjustWorkAreaRequest:
      type: object
      description: Request body for `POST /api/v1/template-converter/adjust-work-area`.
      required:
      - callbackId
      - slideIndex
      - selection
      properties:
        callbackId:
          type: string
          minLength: 1
          description: Conversion job id. Must correspond to a live conversion session.
        slideIndex:
          type: integer
          minimum: 0
          description: Zero-based slide index.
        selection:
          type: string
          description: The work-area option to apply. Must be one of the options currently available for
            this slide, as returned by `GET /api/v1/template-converter/work-area-options`.
      additionalProperties: true
    TemplateConverterUpdateLayoutRequest:
      type: object
      description: Request body for `POST /api/v1/template-converter/update-layout`.
      required:
      - callbackId
      - slideIndex
      - layoutId
      - source
      properties:
        callbackId:
          type: string
          minLength: 1
          description: Conversion job id. Must correspond to a live conversion session.
        slideIndex:
          type: array
          minItems: 1
          description: Zero-based indices of the slides to update. Must be an array with at least one
            element, even for a single slide.
          items:
            type: integer
            minimum: 0
        layoutId:
          type: string
          minLength: 1
          description: Target layout id, taken from `GET /api/v1/template-converter/layouts`.
        source:
          type: string
          enum:
          - targetTemplateLayouts
          - inputDeckLayouts
          description: Which layout collection `layoutId` belongs to.
      additionalProperties: true
    TemplateConverterModifyFormatRequest:
      type: object
      description: 'Request body for `POST /api/v1/template-converter/modify-format`.


        Note the mixed casing — `callbackId` and `slideIndex` are

        camelCase, while `selection_type`, `overall_settings_selected`, and

        `modify_format_config` are snake_case.

        '
      required:
      - callbackId
      - slideIndex
      properties:
        callbackId:
          type: string
          minLength: 1
          description: Conversion job id. Must correspond to a live, completed conversion.
        slideIndex:
          type: array
          minItems: 1
          description: Zero-based indices of the slides to restyle. Each value must be within the deck's
            slide count.
          items:
            type: integer
            minimum: 0
        selection_type:
          type: string
          description: How the selection was made. Derived automatically when omitted.
          enum:
          - single
          - all
          - custom
          - apply to slides after the current slide
          - apply to slides before the current slide
        overall_settings_selected:
          type: boolean
          default: false
          description: When `true`, deck-level settings are applied and `modify_format_config` is not
            required. When `false` or omitted, `modify_format_config` is required.
        modify_format_config:
          type: array
          description: 'Per-slide formatting modifications. Required unless

            `overall_settings_selected` is `true`.


            The array length must equal `slideIndex`''s length — entry *i*

            applies to slide `slideIndex[i]`. Each entry must contain

            **either** `title` **or** `body`, never both.

            '
          items:
            type: object
            properties:
              title:
                $ref: '#/components/schemas/TemplateConverterFormatSection'
              body:
                $ref: '#/components/schemas/TemplateConverterFormatSection'
            additionalProperties: true
      additionalProperties: true
    TemplateConverterFormatSection:
      type: object
      description: "Formatting settings for one section (`title` or `body`) of a\nslide. **All seven properties\
        \ are required** — omitting any one is\nrejected.\n\nEach property is an object with `option_type`\
        \ and `value`:\n\n- `option_type: \"target\"` — inherit the target template's value.\n  `value`\
        \ must be an empty string.\n- `option_type: \"custom\"` — override it. `value` must be one of\n\
        \  the allowed values for that property.\n"
      required:
      - font_height
      - font_case
      - font_bold
      - font_italic
      - font_underline
      - vertical_alignment
      - horizontal_alignment
      properties:
        font_height:
          allOf:
          - $ref: '#/components/schemas/TemplateConverterFormatOption'
          - description: Allowed `custom` values — `8`, `9`, `10`, `10.5`, `11`, `12`, `14`, `16`, `18`,
              `20`, `24`, `28`, `32`, `36`, `40`, `44`, `48`, `54`, `60`, `72`, `96`.
        font_case:
          allOf:
          - $ref: '#/components/schemas/TemplateConverterFormatOption'
          - description: Allowed `custom` values — `lowerCase`, `upperCase`, `capitaliseCase`, `sentenceCase`.
        font_bold:
          $ref: '#/components/schemas/TemplateConverterFormatOption'
        font_italic:
          $ref: '#/components/schemas/TemplateConverterFormatOption'
        font_underline:
          $ref: '#/components/schemas/TemplateConverterFormatOption'
        vertical_alignment:
          allOf:
          - $ref: '#/components/schemas/TemplateConverterFormatOption'
          - description: Allowed `custom` values — `top`, `middle`, `bottom`.
        horizontal_alignment:
          allOf:
          - $ref: '#/components/schemas/TemplateConverterFormatOption'
          - description: Allowed `custom` values — `left`, `center`, `right`, `justified`.
      additionalProperties: true
    TemplateConverterFormatOption:
      type: object
      description: One formatting property — either inherited from the target template or overridden with
        a custom value.
      required:
      - option_type
      properties:
        option_type:
          type: string
          enum:
          - target
          - custom
          description: Use `target` to inherit the template's value, or `custom` to override it.
        value:
          description: Empty string when `option_type` is `target`. When `custom`, one of the allowed
            values for the property (an empty string is also accepted).
      additionalProperties: true
    TemplateConverterStartResponse:
      type: object
      description: 'Response body for `POST /api/v1/template-converter/start`.


        This endpoint does **not** use the canonical `success`/`data`

        envelope — the fields below are returned at the **top level**, in

        camelCase.

        '
      required:
      - callbackId
      - status
      properties:
        callbackId:
          type: string
          description: Conversion job id to poll. Note the camelCase spelling.
        status:
          type: string
          enum:
          - processing
          - failed
          description: '`processing` once the pipeline has been accepted; `failed` if it could not be
            started.'
        presentationName:
          type: string
          description: Resolved presentation name. May be an empty string.
        token:
          type: string
          description: Token for callback-id-scoped URLs.
      additionalProperties: true
    TemplateConverterStatusV2SuccessResponse:
      description: 'Response body for

        `GET /api/v1/template-converter/status/{callbackId}`. Returned with

        HTTP 200 whenever the job is found — inspect `status` to determine

        the pipeline''s state.

        '
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - callbackId
            - status
            properties:
              callbackId:
                type: string
                description: The polled callback id.
              status:
                type: string
                description: Current pipeline state — branch on this rather than on the HTTP status.
              presentation_name:
                type: string
                description: Final presentation name.
              template_name:
                type: string
                description: Target template that was applied.
            additionalProperties: true
    TemplateConverterAsyncProcessingResponse:
      type: object
      description: 'Response for endpoints that kick off a derived conversion

        pipeline (update-layout, modify-format, template-change,

        review-suggestions PATCH).


        These endpoints do **not** use the canonical `success`/`data`

        envelope — the fields below are returned at the top level. Poll the

        returned `callbackId` via

        `GET /api/v1/template-converter/status/{callbackId}`.

        '
      required:
      - status
      - callbackId
      properties:
        status:
          type: string
          description: Always "processing" — the derived pipeline has been accepted and is running.
          enum:
          - processing
        callbackId:
          type: string
          description: Callback id of the newly started pipeline. Note the camelCase spelling.
        presentationName:
          type: string
          description: Resolved presentation name. Returned by template-change and the review-suggestions
            PATCH; may be an empty string.
      additionalProperties: true
    TemplateConverterReviewSuggestionsResponse:
      description: Response body for `GET /api/v1/template-converter/{callback_id}/review-suggestions`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - callback_id
            - suggestions
            properties:
              callback_id:
                type: string
                description: The conversion job id.
              presentation_name:
                type: string
                description: Presentation name.
              suggestions:
                type: array
                description: Editorial suggestions.
                items:
                  type: object
                  additionalProperties: true
            additionalProperties: true
    TemplateConverterDownloadResponse:
      description: Response body for `GET /api/v1/template-converter/download/{callbackId}`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - download_url
            - file_name
            properties:
              download_url:
                type: string
                format: uri
                description: Signed download URL.
              file_name:
                type: string
                description: Filename of the converted deck.
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    TemplateConverterFinalprocessResponse:
      type: object
      description: 'Response body for `POST /api/v1/template-converter/finalprocess`.


        The payload is nested under `data`, but the envelope uses `status`

        and `log` rather than `success`, and the `data` fields are

        **camelCase**.

        '
      required:
      - data
      properties:
        status:
          type: string
          enum:
          - success
          description: Upload status.
        log:
          type: string
          description: Human-readable confirmation, for example "File uploaded successfully".
        data:
          type: object
          required:
          - fileId
          properties:
            fileId:
              type: string
              description: Identifier of the assembled file. Pass this as `fileId` to `POST /api/v1/template-converter/start`.
            s3Prefix:
              type: string
              description: S3 key prefix of the assembled file.
            s3Bucket:
              type: string
              description: S3 bucket of the assembled file.
            type:
              type: string
              description: Detected file type.
            sizeKb:
              type: integer
              description: File size in kilobytes.
            numOfPages:
              type: integer
              description: Number of pages/slides.
          additionalProperties: true
      additionalProperties: true
    TemplateConverterGenericResponse:
      description: Generic success envelope for Template Converter endpoints whose data is opaque or message-only
        (for example adjust-work-area).
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            properties:
              message:
                type: string
                description: Human-readable confirmation.
            additionalProperties: true
    TemplateConverterReactionFeedbackResponse:
      description: Response body for `PUT /api/v1/template-converter/reaction-feedback`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            properties:
              callback_id:
                type: string
                description: The deck callback id.
              type:
                type: string
                enum:
                - liked
                - feedback
                description: Reaction kind.
              message:
                type: string
                description: Human-readable confirmation.
              warnings:
                type: array
                description: Optional non-fatal warnings.
                items:
                  type: string
            additionalProperties: true
    TemplateConverterWorkAreaOptionsResponse:
      description: Response body for `GET /api/v1/template-converter/work-area-options`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - callback_id
            - work_area_adjustments
            properties:
              callback_id:
                type: string
                description: The conversion job id.
              work_area_adjustments:
                type: array
                description: Available work-area adjustments for the requested slide.
                items:
                  type: object
                  additionalProperties: true
            additionalProperties: true
    TemplateConverterLayoutsResponse:
      description: Response body for `GET /api/v1/template-converter/layouts`.
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - callback_id
            - status
            - layouts
            properties:
              callback_id:
                type: string
                description: The conversion job id.
              status:
                type: string
                enum:
                - success
                - in_progress
                - failed
                description: Status of the layout-fetch step.
              layouts:
                type: object
                description: Available layouts for the target template and input deck.
                properties:
                  target_template_layouts:
                    type: array
                    description: Layouts from the target template.
                    items:
                      type: object
                      additionalProperties: true
                  input_deck_layouts:
                    type: array
                    description: Layouts inferred from the input deck.
                    items:
                      type: object
                      additionalProperties: true
                additionalProperties: true
            additionalProperties: true
    TemplateConverterModifyFormatSettingsResponse:
      type: object
      description: 'Response body for

        `GET /api/v1/template-converter/modify-format-settings`.


        This endpoint does **not** use the canonical `success`/`data`

        envelope — the fields below are returned at the **top level**.

        '
      required:
      - callbackId
      - modify_format_settings
      properties:
        callbackId:
          type: string
          description: The conversion job id. Note the camelCase spelling.
        modify_format_settings:
          type: array
          description: Current title/body formatting settings, one entry per slide. Use these as the starting
            point for a `POST /api/v1/template-converter/modify-format` request.
          items:
            type: object
            additionalProperties: true
      additionalProperties: true
    WebhookEventType:
      type: string
      description: 'Catalog of event types emitted by Prezent. New types may be

        added without notice; clients should ignore unknown values.

        '
      enum:
      - autogeneration.completed
      - autogeneration.failed
      - template_conversion.completed
      - template_conversion.failed
      - webhook.test
    WebhookSubscriptionStatus:
      type: string
      enum:
      - active
      - disabled
      description: '`active` subscriptions receive deliveries. `disabled`

        subscriptions are skipped at dispatch time — either explicitly

        set by the customer or set by Prezent''s auto-disable rule after

        50 consecutive delivery failures. PATCH `status: active` to

        re-enable.

        '
    WebhookSubscription:
      type: object
      description: 'Core read-shape for a webhook subscription. Returned by GET +

        PATCH endpoints. Never includes the raw HMAC secret — only

        `secret_prefix` (the first 6 chars, for human disambiguation).

        '
      required:
      - id
      - url
      - secret_prefix
      - events
      - status
      - created_at
      - updated_at
      properties:
        id:
          type: string
          pattern: ^whsub_[a-f0-9]{32}$
          example: whsub_3f7a9b1c8d2e4f5a6b7c8d9e0f1a2b3c
        url:
          type: string
          format: uri
          description: HTTPS endpoint receiving signed deliveries.
          example: https://hooks.example.com/prezent
        secret_prefix:
          type: string
          description: First 6 characters of the HMAC secret, for human disambiguation. Always `whsec_`
            for current implementations.
          example: whsec_
        events:
          type: array
          description: 'Event types this subscription receives. Use `["*"]` to

            subscribe to everything, including future event types.

            '
          items:
            $ref: '#/components/schemas/WebhookEventType'
          minItems: 1
          example:
          - autogeneration.completed
          - autogeneration.failed
        description:
          type: string
          nullable: true
          description: Free-form human label for the subscription.
          example: Push completions into our deal-room worker.
        status:
          $ref: '#/components/schemas/WebhookSubscriptionStatus'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        last_delivery_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp of the most recent successful delivery.
        last_failure_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp of the most recent failed delivery.
        consecutive_failure_count:
          type: integer
          format: int32
          minimum: 0
          description: 'Failures since the last successful delivery. At 50 the

            subscription is auto-disabled.

            '
      additionalProperties: true
    StreamSessionCreateRequest:
      type: object
      required:
      - callback_id
      properties:
        callback_id:
          type: string
          description: 'The `callback_id` returned by your earlier call to

            `POST /api/v1/autogenerator` (or other async endpoint).

            The calling API key must own this job.

            '
          example: cb_01HZQ3Y7K3D6V0A0CS7HD3
    StreamSessionCreateResponse:
      type: object
      required:
      - success
      - data
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          required:
          - session_id
          - stream_url
          - expires_at
          properties:
            session_id:
              type: string
              description: Same as the `callback_id` you passed in.
              example: cb_01HZQ3Y7K3D6V0A0CS7HD3
            stream_url:
              type: string
              format: uri
              description: 'Open with `new EventSource(stream_url)` (or `fetch`

                + ReadableStream). Hostname is environment-dependent

                (e.g. `stream-api.myprezent.com`). The embedded token

                expires at `expires_at`.

                '
              example: https://stream-api.myprezent.com/v1/streams/cb_01HZQ3Y7K3D6V0A0CS7HD3?token=eyJhbGciOi...
            expires_at:
              type: string
              format: date-time
              description: When the embedded token stops being accepted. Call this endpoint again to refresh.
              example: '2026-06-09T10:05:00Z'
    WebhookSubscriptionCreateRequest:
      type: object
      required:
      - url
      properties:
        url:
          type: string
          format: uri
          description: 'HTTPS endpoint to receive deliveries. Must use `https://`,

            resolve to a public IP, and not use a disallowed port. See

            the [Webhooks guide](/docs/webhooks#url-requirements).

            '
          example: https://hooks.example.com/prezent
        events:
          type: array
          description: Event types to subscribe to. Defaults to `["*"]`.
          items:
            $ref: '#/components/schemas/WebhookEventType'
          default:
          - '*'
          example:
          - autogeneration.completed
          - autogeneration.failed
        description:
          type: string
          nullable: true
          example: Push completions into our deal-room worker.
        status:
          $ref: '#/components/schemas/WebhookSubscriptionStatus'
      additionalProperties: false
    WebhookSubscriptionUpdateRequest:
      type: object
      description: Partial update. Any combination of fields may be supplied.
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            $ref: '#/components/schemas/WebhookEventType'
          minItems: 1
        description:
          type: string
          nullable: true
        status:
          $ref: '#/components/schemas/WebhookSubscriptionStatus'
      additionalProperties: false
    WebhookSubscriptionCreateResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            allOf:
            - $ref: '#/components/schemas/WebhookSubscription'
            - type: object
              required:
              - secret
              properties:
                secret:
                  type: string
                  description: 'The raw HMAC secret. Returned ONCE on this

                    endpoint and on `/rotate-secret`. Store it

                    immediately — subsequent reads expose only

                    `secret_prefix`.

                    '
                  example: whsec_4mZkV8t9oFp1qR3sT7uW9xY2zA5bCdEfGhI
    WebhookSubscriptionReadResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            $ref: '#/components/schemas/WebhookSubscription'
    WebhookSubscriptionListResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - items
            properties:
              items:
                type: array
                items:
                  $ref: '#/components/schemas/WebhookSubscription'
              next_cursor:
                type: string
                nullable: true
                description: Pass to the next call's `cursor` query param. `null` when no more pages.
    WebhookSubscriptionDeleteResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - id
            - deleted
            properties:
              id:
                type: string
                example: whsub_3f7a9b1c8d2e4f5a6b7c8d9e0f1a2b3c
              deleted:
                type: boolean
                const: true
    WebhookSubscriptionRotateResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - id
            - secret
            - secret_prefix
            - rotated_at
            properties:
              id:
                type: string
                example: whsub_3f7a9b1c8d2e4f5a6b7c8d9e0f1a2b3c
              secret:
                type: string
                description: The freshly-issued HMAC secret. Stored nowhere by Prezent after this response
                  — capture it before forwarding.
                example: whsec_NewlyGeneratedSecretMaterial
              secret_prefix:
                type: string
                example: whsec_
              rotated_at:
                type: string
                format: date-time
    WebhookSubscriptionTestResponse:
      allOf:
      - $ref: '#/components/schemas/SuccessEnvelope'
      - type: object
        properties:
          data:
            type: object
            required:
            - subscription_id
            - event
            - delivery
            properties:
              subscription_id:
                type: string
                example: whsub_3f7a9b1c8d2e4f5a6b7c8d9e0f1a2b3c
              event:
                $ref: '#/components/schemas/WebhookEvent'
              delivery:
                type: object
                required:
                - ok
                - status
                - delivery_id
                properties:
                  ok:
                    type: boolean
                    description: True if the receiver returned a 2xx.
                  status:
                    type: integer
                    description: HTTP status code from the receiver (0 on network error / timeout).
                    example: 200
                  error:
                    type: string
                    nullable: true
                    description: Network error code (`timeout`, `ECONNREFUSED`, etc.). `null` on success.
                  response_body_preview:
                    type: string
                    description: First 8 KiB of the receiver's response body, for debugging.
                  delivery_id:
                    type: string
                    pattern: ^whdl_[a-f0-9]{24}$
                    description: Internal delivery id. Also sent to the receiver in the `X-Prezent-Delivery`
                      header.
    WebhookEvent:
      type: object
      description: 'Payload **POSTed to your subscription URL**. This is NOT the

        body of any management endpoint — it is what your receiver

        parses. Verify the signature first; see the [Webhooks

        guide](/docs/webhooks#4-verify-the-signature).

        '
      required:
      - id
      - type
      - api_version
      - created_at
      - data
      properties:
        id:
          type: string
          pattern: ^evt_[a-zA-Z0-9_]+$
          description: Globally unique event identifier. Also sent in the `X-Prezent-Event` header. Dedupe
            on this if you receive the same event twice (at-least-once delivery).
          example: evt_8c2a1f7e6d3b4a5c9e0f8d7b6a5c4d3e
        type:
          $ref: '#/components/schemas/WebhookEventType'
        api_version:
          type: string
          description: Schema version for the `data` field. Increments only on breaking changes; legacy
            versions remain available.
          example: '1.0'
        created_at:
          type: string
          format: date-time
        data:
          type: object
          description: 'Event-specific payload. For `autogeneration.*` events,

            contains `callback_id`, `report_id`, `status`, plus

            `outputs` (on success) or `error_log` (on failure). For

            `template_conversion.*` events, contains the conversion

            `callback_id`, `status`, and output URLs.

            '
          additionalProperties: true
    GenerationContextFile:
      type: object
      description: Reference to a file you previously uploaded.
      required:
      - file_id
      properties:
        file_id:
          type: string
          description: Id returned when the file was uploaded.
          example: 7f1c9a52-3e44-4a1b-9c88-2d5e6f0a1b23
      additionalProperties: true
    GenerationSettingsV2:
      type: object
      description: 'Generation settings. **Every key is optional.** An omitted key falls back

        to the default configured on your API key, and then to the documented

        default — so a fully configured key needs no `settings` object at all.

        '
      properties:
        template_id:
          type: string
          description: 'Brand template to apply. Also settable at the root of the request,

            which takes precedence over this. Falls back to your key''s configured

            template, then your default theme. Validated — an inaccessible

            template is rejected.


            List the templates available to you with

            [`GET /api/v1/autogenerator/templates`](#operation/listAutoGeneratorTemplates).

            '
          example: your-template-id
        language:
          type: string
          description: 'Locale to generate in. Must be one of the locales from

            [`GET /api/v2/autogenerator/languages`](#operation/listLanguagesV2) —

            an unsupported value is rejected with `422`.

            '
          default: en
          example: en
        websearch:
          type: boolean
          description: 'Let the generator search the web for supporting material.


            Also settable at the root of the request as `websearch`/

            `externalContext`, which takes precedence over this.

            '
          default: false
        add_sources_to_footer:
          type: boolean
          description: Cite sources in each slide's footer.
          default: false
        add_sources_to_slides_note:
          type: boolean
          description: 'Cite sources in each slide''s notes.


            Takes precedence over `add_speaker_notes_to_slides_note` — sources and

            speaker notes cannot both occupy the slide notes, so enabling this

            disables that.

            '
          default: false
        generate_speaker_notes:
          type: boolean
          description: Write speaker notes for each slide.
          default: false
        add_speaker_notes_to_slides_note:
          type: boolean
          description: 'Put the speaker notes into the slide notes of the exported file.

            Ignored when `add_sources_to_slides_note` is enabled.

            '
          default: false
        image_library:
          type: object
          description: 'Which image libraries the generator may draw from. Omitted or

            unset libraries default to `false`, except `ai_images`, which

            defaults to `true` when the object itself is omitted.

            `company_library` and `brand_library` are the same library under

            two names — set `brand_library`.

            '
          properties:
            brand_library:
              type: boolean
            prezent_library:
              type: boolean
            ai_images:
              type: boolean
            my_workspace:
              type: boolean
            additional_context:
              type: boolean
          example:
            brand_library: false
            prezent_library: true
            ai_images: true
            my_workspace: false
            additional_context: false
        voice_settings:
          type: object
          description: 'Brand-voice profile to write in. Falls back to the profile configured

            on your key, then the standard voice.

            '
          properties:
            type:
              type: string
              description: Voice profile name.
              example: standard
          additionalProperties: true
        deck_default_size:
          type: integer
          description: 'Slides to aim for. The prompt can override this — asking for "a

            5-slide deck" wins.

            '
          minimum: 1
          maximum: 200
          default: 7
          example: 10
        deck_max_size:
          type: integer
          description: 'Upper bound on slides. Must be greater than or equal to

            `deck_default_size`.

            '
          minimum: 1
          maximum: 200
          default: 100
          example: 20
        export_type:
          type: string
          description: 'Format to export on completion. Also selectable per download on

            [`POST /api/v2/autogenerator/download`](#operation/downloadGenerationV2).

            '
          enum:
          - pptx
          - pdf
          default: pptx
        enable_mcp_context:
          type: boolean
          description: 'Let the generator pull context from your connected apps (Google Drive,

            Notion, …). Connect an app first with

            [`GET /api/v2/integrations/auth`](#operation/getIntegrationAuthUrlV2).

            '
          default: false
      additionalProperties: false
    GenerateV2Request:
      type: object
      required:
      - prompt
      properties:
        prompt:
          type: string
          minLength: 1
          description: 'What to generate, in plain language. Be specific about topic,

            audience, and length — "a 10-slide deck on renewable-energy market

            trends for a board audience" produces a better result than

            "renewable energy".

            '
          example: A 10-slide deck on renewable-energy market trends for 2026
        template_id:
          type: string
          description: 'Brand template to apply. Takes precedence over `settings.template_id`.

            Falls back to your key''s configured template, then your default theme.

            '
          example: your-template-id
        audience_id:
          type: string
          description: 'Audience profile to tailor the deck to (tone, detail, structure). List

            available profiles with

            [`GET /api/v1/audiences`](#operation/listAudiences).

            '
          example: 9b2e1f74-55aa-4c0d-8f31-6ab7c9d20e15
        audience:
          type: object
          description: Object form of `audience_id`. `audience_id` takes precedence.
          properties:
            id:
              type: string
          example:
            id: 9b2e1f74-55aa-4c0d-8f31-6ab7c9d20e15
        files:
          type: array
          description: 'Files to ground the generation in. Upload them first with

            [`POST /api/v1/preprocess`](#operation/preprocessFile), then pass the

            ids here.

            '
          items:
            $ref: '#/components/schemas/GenerationContextFile'
        web_links:
          type: array
          description: URLs for the generator to read as source material.
          items:
            type: string
            format: uri
          example:
          - https://example.com/market-report-2026
        text:
          type: string
          description: 'A block of text to use as source material — notes, an outline, an

            excerpt. Use `texts` to pass several.

            '
          example: Our internal target was 12% growth in the EMEA region.
        texts:
          type: array
          description: 'Several blocks of text as source material. Takes precedence over

            `text`.

            '
          items:
            type: string
        websearch:
          type: boolean
          description: 'Let the generator search the web. Takes precedence over

            `settings.websearch`.

            '
          default: false
        externalContext:
          type: boolean
          description: Alias for `websearch`.
        settings:
          $ref: '#/components/schemas/GenerationSettingsV2'
      additionalProperties: false
    GenerateV2Response:
      type: object
      description: 'Note the envelope: the payload is under **`resData`**, not `data`.

        '
      required:
      - message
      - resData
      properties:
        message:
          type: string
          example: Job submitted successfully
        resData:
          type: object
          required:
          - callback_id
          properties:
            callback_id:
              type: string
              description: 'Identifies this generation. Pass it to

                [`POST /api/v2/streams/sessions`](#operation/createStreamSessionV2)

                to stream progress and obtain the deck, to

                [`POST /api/v2/autogenerator/edit`](#operation/editGenerationV2) to

                revise it, and to

                [`POST /api/v2/autogenerator/download`](#operation/downloadGenerationV2)

                to fetch the file.


                Valid for about 3 hours.

                '
              example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
          additionalProperties: true
        error:
          type:
          - 'null'
          - string
          description: '`null` on success.'
      additionalProperties: true
    EditV2Request:
      type: object
      required:
      - callback_id
      - prompt
      properties:
        callback_id:
          type: string
          minLength: 1
          description: 'The presentation to edit — the `callback_id` of the original

            generation, or of the most recent edit.

            '
          example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
        prompt:
          type: string
          minLength: 1
          description: 'The change to make, in plain language.

            '
          example: Make the tone more formal and shorten every bullet
        slideIndex:
          type: integer
          minimum: 0
          description: 'Which slide to edit, counting from **0**. Omit to edit the deck as a

            whole.


            Must be within the deck — a value past the last slide is rejected with

            `400` reporting the actual slide count.

            '
          example: 4
        files:
          type: array
          description: Files to use as context for this edit.
          items:
            $ref: '#/components/schemas/GenerationContextFile'
        web_links:
          type: array
          description: URLs to read as context for this edit.
          items:
            type: string
            format: uri
        text:
          type: string
          description: A block of text to use as context for this edit.
          example: Q4 revenue closed at $4.2M, up 18% year over year.
      additionalProperties: false
    EditV2Response:
      type: object
      description: 'Same envelope as generate — payload under **`resData`**.

        '
      required:
      - message
      - resData
      properties:
        message:
          type: string
          example: Edit submitted successfully
        resData:
          type: object
          required:
          - callback_id
          properties:
            callback_id:
              type: string
              description: 'A **new** id for this edit turn — not the one you sent. Stream it

                to watch the edit, and pass it as the `callback_id` of your next

                edit to keep building on this version.

                '
              example: 8c1d4b92-6f37-4e2a-a95c-1b0e7d3f6a48
          additionalProperties: true
        error:
          type:
          - 'null'
          - string
          description: '`null` on success.'
      additionalProperties: true
    DownloadV2Request:
      type: object
      required:
      - callback_id
      properties:
        callback_id:
          type: string
          minLength: 1
          description: The presentation to download.
          example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
        export_type:
          type: string
          description: 'File format. Defaults to the format configured on your API key, and

            then to `pptx`.

            '
          enum:
          - pptx
          - pdf
          example: pdf
      additionalProperties: false
    DownloadV2Response:
      type: object
      description: 'Flat response — fields are at the top level, not under `data`.

        '
      required:
      - message
      - status
      - callback_id
      - export_type
      - stream_url
      - expires_at
      properties:
        message:
          type: string
          example: Connect to stream_url to receive the download URL on the done event
        status:
          type: string
          enum:
          - success
          description: 'Confirms the stream was minted. It does **not** mean the file is

            ready — read the stream''s terminal event for that.

            '
        callback_id:
          type: string
          example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
        export_type:
          type: string
          enum:
          - pptx
          - pdf
          description: The format that was resolved for this download.
        stream_url:
          type: string
          format: uri
          description: 'Authenticated SSE URL. Open it and read the terminal `done` event for

            the `download_url`. The token is in the URL — send no

            `Authorization` header.

            '
          example: https://stream-api-prod.myprezent.com/v2/streams/a1b2c3?token=eyJhbGciOi...&turn_id=3f8e7d61&stream_type=export&export_type=pptx
        expires_at:
          type: string
          format: date-time
          description: 'When `stream_url` stops working (about 5 minutes out). Past this, call

            this endpoint again for a fresh URL.

            '
          example: '2026-08-05T12:34:56.000Z'
      additionalProperties: true
    StreamSessionV2Request:
      type: object
      required:
      - callback_id
      properties:
        callback_id:
          type: string
          minLength: 1
          description: 'The `callback_id` from

            [generate](#operation/createGenerationV2) or

            [edit](#operation/editGenerationV2).

            '
          example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
      additionalProperties: false
    StreamSessionV2Response:
      type: object
      description: Canonical envelope — payload under `data`.
      required:
      - success
      - data
      properties:
        success:
          type: boolean
          enum:
          - true
        data:
          type: object
          required:
          - callback_id
          - stream_url
          - expires_at
          properties:
            callback_id:
              type: string
              example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
            stream_url:
              type: string
              format: uri
              description: 'Authenticated SSE URL. Open it with any SSE client — the token is

                in the URL, so send no `Authorization` header.


                For an edit, the URL also replays the stream from the point the

                edit was queued, so you see the whole turn even if you connect a

                moment late.

                '
              example: https://stream-api-prod.myprezent.com/v2/streams/a1b2c3?token=eyJhbGciOi...&turn_id=3f8e7d61
            expires_at:
              type: string
              format: date-time
              description: 'When `stream_url` stops working (about 5 minutes out). Call this

                endpoint again for a fresh URL — the stream replays from the start

                of the turn, so nothing is lost.

                '
              example: '2026-08-05T12:34:56.000Z'
          additionalProperties: true
      additionalProperties: true
    StreamEventV2:
      type: object
      description: 'One event on a v2 stream. Every event — progress and terminal alike — has

        this shape, so a single parser handles the whole stream.


        Progress events carry `status: "inprogress"`. The final event carries

        `success`, `failed`, or `cancelled`, and the stream closes after it. A

        successful final event adds `download_url`.


        The SSE `event:` name is `status` for progress events, and `done`,

        `error`, or `cancelled` for the terminal one — but branching on the

        `status` field is simpler and equivalent.

        '
      required:
      - status
      - message
      - callback_id
      properties:
        status:
          type: string
          enum:
          - inprogress
          - success
          - failed
          - cancelled
          description: '`inprogress` while working. Then exactly one of `success`, `failed`,

            or `cancelled`, after which the stream closes.

            '
        message:
          type: string
          description: 'Human-readable description of the current step, safe to show a user

            verbatim. Progress messages are drawn from a fixed set, in order:

            "Understanding your prompt", "Checking for app references" (only when

            the prompt references a connected app), "Analyzing the key elements",

            "Adjusting structure for clarity", "Optimizing spacing and alignment",

            "Crafting your speaker notes" (only when notes were requested),

            "Finalizing your slides".


            Steps that do not apply to your request are skipped, so do not treat

            the list as a fixed-length progress bar. On a `failed` event this

            carries the reason.

            '
          example: Analyzing the key elements
        callback_id:
          type: string
          description: The generation or edit turn this event belongs to.
          example: 3f8e7d61-9a2b-4c5e-b013-7d4a6f2c8e91
        download_url:
          type:
          - 'null'
          - string
          description: 'Present only on a `success` event. The finished presentation.


            May be `null` on a generation stream when the file has not been

            exported yet — call

            [`POST /api/v2/autogenerator/download`](#operation/downloadGenerationV2)

            to produce it. On a download stream it is always populated.

            '
          example: https://cdn.prezent.ai/exports/a1b2c3/deck.pptx?token=...
      additionalProperties: true
    LanguageV2:
      type: object
      required:
      - language
      - locale
      properties:
        language:
          type: string
          description: Display name.
          example: English (US)
        locale:
          type: string
          description: Value to pass as `settings.language`.
          example: en
      additionalProperties: true
    LanguagesV2Response:
      type: object
      description: 'Note the envelope: `status` and `message` at the top level, with the list

        under `data`.

        '
      required:
      - status
      - data
      properties:
        status:
          type: string
          enum:
          - success
        message:
          type: string
          example: Supported languages retrieved successfully
        data:
          type: array
          items:
            $ref: '#/components/schemas/LanguageV2'
          example:
          - language: Arabic
            locale: ar
          - language: Chinese (Simplified)
            locale: zh
          - language: English (UK)
            locale: en-uk
          - language: English (US)
            locale: en
          - language: French
            locale: fr
          - language: German
            locale: de
          - language: Hindi
            locale: hi
          - language: Indonesian
            locale: id
          - language: Italian
            locale: it
          - language: Japanese
            locale: ja
          - language: Korean
            locale: ko
          - language: Portuguese (Brazil)
            locale: pt
          - language: Spanish
            locale: es
      additionalProperties: true
    IntegrationAuthV2Response:
      description: 'One of two shapes, depending on whether the app needs authorization.

        Branch on the presence of `status`.

        '
      oneOf:
      - type: object
        title: Authorization required
        description: Open `auth_url` to authorize the app.
        required:
        - auth_url
        properties:
          auth_url:
            type: string
            format: uri
            description: 'URL for the user to open and authorize. Single-use and

              time-limited — request a fresh one rather than storing it.

              '
        additionalProperties: true
      - type: object
        title: Connected
        description: 'The app needs no authorization and is now connected. Nothing further

          to do.

          '
        required:
        - status
        properties:
          status:
            type: string
            enum:
            - connected
          message:
            type: string
            example: MCP connection successful
        additionalProperties: true
    IntegrationAuthStatusV2Response:
      type: object
      description: 'Flat response from the integrations service. `connected` is the field to

        read.

        '
      properties:
        connected:
          type: boolean
          description: Whether this app is currently connected for the caller.
      additionalProperties: true
  responses:
    BadRequest:
      description: Generic client error. `error.code` is one of `BAD_REQUEST`, `INVALID_JSON`, `MISSING_REQUIRED_FIELD`,
        `MISSING_QUERY_PARAM`, `MISSING_CALLBACK_ID`, `MISSING_SLIDES_ARRAY`, `MISSING_PROMPT`, `MISSING_TEMPLATE_ID`,
        `MISSING_FILE_CONTENT`, `MISSING_SHARE_DETAILS`, `INVALID_TYPE`, `INVALID_DATA`, `INVALID_DATA_TYPE`,
        `INVALID_PAYLOAD`, `INVALID_REQUEST`, `API_REQUEST_FAILED`, or `FILE_UPLOAD_FAILED`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: BAD_REQUEST
              message: Bad request.
              details: {}
    Unauthorized:
      description: 'Caller did not present a valid Bearer token, or the token has

        expired. `error.code` is one of `UNAUTHORIZED`, `INVALID_API_KEY`,

        `EXPIRED_API_KEY`.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: INVALID_API_KEY
              message: API key not found or not authorized.
              details: {}
    Forbidden:
      description: Caller is authenticated but not allowed to perform this operation. `error.code` is
        `FORBIDDEN`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: FORBIDDEN
              message: Access to the resource is forbidden.
              details: {}
    NotFound:
      description: 'Requested endpoint or resource does not exist. `error.code` is

        one of `ENDPOINT_NOT_FOUND`, `RESOURCE_NOT_FOUND`, `NOT_FOUND`.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: RESOURCE_NOT_FOUND
              message: The requested resource was not found.
              details: {}
    MethodNotAllowed:
      description: HTTP method not allowed for this endpoint. `error.code` is `METHOD_NOT_ALLOWED`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: METHOD_NOT_ALLOWED
              message: HTTP method not allowed.
              details: {}
    UnsupportedFileType:
      description: Uploaded file's extension or MIME type is not accepted. `error.code` is `UNSUPPORTED_FILE_TYPE`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: UNSUPPORTED_FILE_TYPE
              message: Unsupported file type.
              details: {}
    UnprocessableEntity:
      description: 'Request was well-formed but failed semantic validation.

        `error.code` is one of `INVALID_INPUT`, `UNPROCESSABLE_ENTITY`.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: INVALID_INPUT
              message: Invalid input provided.
              details: {}
    IdempotencyConflict:
      description: 'The supplied `Idempotency-Key` was already used with a different

        request body. Reuse a key only for identical retried requests.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_BODY
              message: This Idempotency-Key was already used with a different request body.
              details: {}
    RateLimited:
      description: "Rate limit, usage limit, or gateway-level throttle exceeded.\n`error.code` is `TOO_MANY_REQUESTS`\
        \ (gateway throttle),\n`RATE_LIMIT_EXCEEDED` (per-category), or `USAGE_LIMIT_EXCEEDED`\n(annual\
        \ quota).\n\nDefault limits (all configurable per company/key):\n- Gateway throttle (per API key)\
        \ → `TOO_MANY_REQUESTS`: 10 requests/second\n  sustained, 5 burst, 1,000 requests/day.\n- Per-company,\
        \ per-category sliding 60-second window →\n  `RATE_LIMIT_EXCEEDED`. The applicable category is\
        \ given by each\n  operation's `x-rate-limit-category`.\n- Annual usage quota → `USAGE_LIMIT_EXCEEDED`:\
        \ 50,000 slide\n  generations/year and 1,000,000 presentation downloads/year.\n\n`X-RateLimit-Limit`/`X-RateLimit-Remaining`/`X-RateLimit-Reset`\
        \ are\nreturned on successful (2xx) responses from rate-limited endpoints\nand, with `Retry-After`,\
        \ on the per-category `RATE_LIMIT_EXCEEDED`\n429 (the headers declared below). The gateway `TOO_MANY_REQUESTS`\n\
        and annual `USAGE_LIMIT_EXCEEDED` responses do not carry them. Read\n`X-RateLimit-Remaining` to\
        \ self-throttle and honour `Retry-After` on\na 429.\n"
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/XRateLimitLimit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/XRateLimitRemaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/XRateLimitReset'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: RATE_LIMIT_EXCEEDED
              message: Rate limit exceeded for this category. Try again later.
              details:
                category: auto_generator
                retry_after_seconds: 12
    InternalServerError:
      description: Unexpected server error. `error.code` is `INTERNAL_SERVER_ERROR`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: INTERNAL_SERVER_ERROR
              message: An unexpected server error occurred.
              details: {}
    ServiceUnavailable:
      description: Service is temporarily unavailable (downstream dependency unhealthy). `error.code`
        is `SERVICE_UNAVAILABLE` or `EXTERNAL_SERVICE_ERROR`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: SERVICE_UNAVAILABLE
              message: Service is temporarily unavailable.
              details: {}
    GatewayTimeout:
      description: A downstream call timed out. `error.code` is `GATEWAY_TIMEOUT`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            success: false
            data: null
            error:
              code: GATEWAY_TIMEOUT
              message: Gateway timeout.
              details: {}
