> ## Documentation Index
> Fetch the complete documentation index at: https://developer.demand-iq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a presentation

> Creates a personalized presentation. Provide `homeowner`, `prospect_id`, or both — at least one is required. With only `homeowner`, a new prospect is created from it. With only `prospect_id`, homeowner data is fetched from that prospect's journey. With both, the supplied homeowner data is used as-is and the existing prospect is attached (it must be visible to your credential — otherwise 422 `PROSPECT_NOT_FOUND`). The address is validated via Google Geocoding. Returns a shareable URL immediately; audio generation may continue in the background.

Price inputs are optional. If a product pricing slide uses formula variables that are not supplied, the price is deferred — the slide displays a placeholder instead of failing. Deferred prices can be resolved later when the missing values become available (e.g., after roof measurements). AI Presentations defers a measurement-backed variable only when a formula on one of the deck's product-pricing slides references it. Price variables left in the deck's settings after their product slide was removed, or after its formula stopped referencing them, are ignored. While the deck itself is still being generated, the request is refused with 409 `DECK_GENERATING`: a presentation is a permanent snapshot of the deck at creation time, so one taken mid-generation would be permanently missing slides. Retry once the generation job completes.



## OpenAPI

````yaml /openapi.json post /api/decks/{deckId}/presentations
openapi: 3.0.0
info:
  title: AI Presentations API
  version: 1.0.0
  description: >-
    REST API for AI Presentations — an AI-powered presentation platform with
    narrated slides, live Q&A, and deck management.


    **Authentication**: Most endpoints require a session cookie obtained from
    `POST /api/auth/login`. Presentation playback endpoints (`/api/qa`,
    `/api/narration/*`) also accept a `presentationId` for unauthenticated
    viewer access.
  contact:
    name: Demand IQ
    url: https://demand-iq.com
servers:
  - url: https://app.demand-iq.com
    description: Production
  - url: http://localhost:3000
    description: Local development
security: []
tags:
  - name: Decks
    description: Manage presentation decks
  - name: Slides
    description: Manage slides within a deck
  - name: FAQs
    description: Manage pre-built Q&A pairs
  - name: Branding
    description: Colors, logo, and call-to-action configuration
  - name: Q&A
    description: Live question answering and Q&A settings
  - name: Narration
    description: Text-to-speech synthesis
  - name: Presentations
    description: Create and manage personalized presentation instances
  - name: Generation
    description: AI-powered content generation from slide images
  - name: Images
    description: Image upload and management
  - name: Voices
    description: Available TTS voices
  - name: Utility
    description: Health check and diagnostics
  - name: Authentication
    description: Session-based login, logout, and identity
  - name: Company
    description: Organization contact info and knowledge base
  - name: Notifications
    description: Event subscriptions and delivery log
  - name: Contracts
    description: Contract template import and e-signature
  - name: Fonts
    description: Available Google Fonts for branding
  - name: Roof Measurements
    description: Request and track automated roof measurements
  - name: Actions
    description: Voice/text command detection for presentation control
  - name: Appointments
    description: Appointment scheduling for presentation viewers
  - name: Activity
    description: Recent presentation activity feed
  - name: Onboarding
    description: >-
      Per-user product onboarding milestones (ENG-641). Milestone endpoints are
      idempotent and are called by the app UI — they should not be treated as
      tenant-integration surface.
paths:
  /api/decks/{deckId}/presentations:
    post:
      tags:
        - Presentations
      summary: Create a presentation
      description: >-
        Creates a personalized presentation. Provide `homeowner`, `prospect_id`,
        or both — at least one is required. With only `homeowner`, a new
        prospect is created from it. With only `prospect_id`, homeowner data is
        fetched from that prospect's journey. With both, the supplied homeowner
        data is used as-is and the existing prospect is attached (it must be
        visible to your credential — otherwise 422 `PROSPECT_NOT_FOUND`). The
        address is validated via Google Geocoding. Returns a shareable URL
        immediately; audio generation may continue in the background.


        Price inputs are optional. If a product pricing slide uses formula
        variables that are not supplied, the price is deferred — the slide
        displays a placeholder instead of failing. Deferred prices can be
        resolved later when the missing values become available (e.g., after
        roof measurements). AI Presentations defers a measurement-backed
        variable only when a formula on one of the deck's product-pricing slides
        references it. Price variables left in the deck's settings after their
        product slide was removed, or after its formula stopped referencing
        them, are ignored. While the deck itself is still being generated, the
        request is refused with 409 `DECK_GENERATING`: a presentation is a
        permanent snapshot of the deck at creation time, so one taken
        mid-generation would be permanently missing slides. Retry once the
        generation job completes.
      parameters:
        - in: path
          name: deckId
          required: true
          schema:
            type: string
            format: uuid
          description: UUID of the deck
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                homeowner:
                  $ref: '#/components/schemas/HomeownerData'
                prospect_id:
                  type: string
                  format: uuid
                  description: >-
                    Prospect to attach the presentation to. Alone, homeowner
                    data is fetched from the prospect's journey; with
                    `homeowner`, the prospect is attached and the supplied data
                    is used as-is. Must be visible to your credential.
                voice_settings:
                  type: object
                language_settings:
                  type: object
                price_inputs:
                  type: object
                  additionalProperties:
                    type: number
                  description: >-
                    Values for deck-level price variables (used to evaluate
                    formulas). Optional — omitted variables result in deferred
                    pricing rather than an error.
                measurement_strategy:
                  type: string
                  enum:
                    - manual
                    - auto
                  default: manual
                  description: >-
                    Set to `auto` to resolve measurement-backed price variables
                    from automated roof measurements instead of supplying them
                    in `price_inputs`. Only variables referenced by a formula on
                    the deck's product-pricing slides are deferred to
                    measurements.
      responses:
        '200':
          description: Presentation created
          content:
            application/json:
              schema:
                type: object
                properties:
                  deck_presentation_id:
                    type: string
                    format: uuid
                  url:
                    type: string
                    format: uri
                    description: Shareable presentation URL
                  status:
                    type: string
                    enum:
                      - not_started
                      - pending
                      - processing
                      - ready
                      - failed
        '400':
          description: >-
            Bad request — malformed input, or the deck has no slides (`"Deck has
            no slides"`). A presentation cannot be created from an empty deck.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Conflict: `DECK_GENERATING` — the deck is still being generated.
            This check runs before the empty-deck check, so a job that has not
            written its first slide yet returns 409, not 400. Transient; retry
            once the job settles.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
                    enum:
                      - DECK_GENERATING
        '422':
          description: >-
            Unprocessable: `INVALID_ADDRESS` (address could not be verified),
            `PROSPECT_NOT_FOUND` (prospect_id does not exist or belongs to
            another organization — permanent, do not retry), or
            `PROSPECT_CREATE_FAILED` (prospect data was rejected upstream)
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
                    enum:
                      - INVALID_ADDRESS
                      - PROSPECT_NOT_FOUND
                      - PROSPECT_CREATE_FAILED
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Upstream service is unreachable — retry with backoff
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - sessionCookie: []
components:
  schemas:
    HomeownerData:
      type: object
      properties:
        first_name:
          type: string
        last_name:
          type: string
        address:
          type: string
        city:
          type: string
        state:
          type: string
        zip:
          type: string
        country:
          type: string
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 country code
          example: US
        email:
          type: string
          format: email
        phone:
          type: string
      required:
        - first_name
        - address
        - city
        - country
    Error:
      type: object
      properties:
        error:
          type: string
      required:
        - error
  securitySchemes:
    sessionCookie:
      type: apiKey
      in: cookie
      name: session
      description: Session cookie obtained from `POST /api/auth/login`.

````