> ## Documentation Index
> Fetch the complete documentation index at: https://developers.demosmith.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a demo



## OpenAPI

````yaml /openapi.json get /demos/{demo_id}
openapi: 3.1.0
info:
  title: Demosmith API
  version: 1.0.0
  description: >-
    Create narrated product demo videos from your own code. You send a URL and a
    task in plain words; an

    agent records a real browser walkthrough of your product, then the video is
    edited, narrated and

    rendered — about 5–20 minutes later you get a video link.


    ## Authentication

    Create an API key on the **Developers** page of the Demosmith app (owners
    and admins, paid plans).

    Send it as a bearer token:


    ```

    Authorization: Bearer dsk_live_…

    ```


    A key acts as the person who created it, inside their organization, and uses
    that plan's minutes.

    Keys are shown once; revoke one from the same page. AI assistants (Claude,
    ChatGPT, Cursor, Claude

    Code) connect through the MCP server at `https://mcp.demosmith.ai/mcp`
    instead.


    ## How a demo runs

    1. Optional: `POST /demos/check` refines your task and asks questions when
    something is unclear. It
       is free and creates nothing.
    2. `POST /demos` creates and starts the demo and returns at once with
    `status: queued`. If the task
       still needs answers you get `422 needs_answers` with a `check_id` and the questions; send the same
       request again with `check_id` and `answers`.
    3. Follow it with **webhooks** (below), or poll `GET /demos/{id}` and wait
    `check_again_in_seconds`
       between requests.
    4. When `status` is `completed`, `video.url` plays the video and
    `video.download_url` downloads it.
       Both expire after 2 hours — fetch the demo again for fresh links.

    Statuses: `queued` → `in_progress` (with `stage`: recording, analyzing,
    narrating, editing,

    rendering) → `completed`, or `failed` / `canceled`. `input_required` means
    the recorder is waiting

    for you (see below).


    ## Logins for the site you record

    Send `site_login: {"username", "password"}` with `POST /demos` (or
    `/demos/check`). It is

    encrypted on arrival, used only by the recorder, never logged and never
    returned. If you send none

    and the recorder reaches a sign-in page, the demo pauses with `status:
    input_required` and an

    `input_request` of kind `login` or `verification_code`. Answer it with

    `POST /demos/{id}/input-requests/{request_id}/answer`, or have a person open
    `answer_url` (the

    demo's page in the app). Answers are single use; an unanswered request
    expires (`expires_at`).


    ## Webhooks

    Register endpoints on the Developers page or with `/webhooks`, or pass
    `callback_url` when you create

    a demo (a callback gets every event except `demo.progress`). Each request is
    a JSON `POST`, signed in

    the [Standard Webhooks](https://www.standardwebhooks.com/) format with your
    organization's signing

    secret (`whsec_…`, on the Developers page):


    ```

    webhook-id: evt_…            # the same on every retry — use it to ignore
    duplicates

    webhook-timestamp: 1767225600

    webhook-signature: v1,<base64 HMAC-SHA256 of "{id}.{timestamp}.{body}">

    ```


    Verify with any Standard Webhooks library, for example in Python:


    ```python

    from standardwebhooks import Webhook

    Webhook(signing_secret).verify(raw_body, headers)

    ```


    Answer with any 2xx within 10 seconds. Failures are retried for about a day
    (30 s, 2 min, 10 min,

    30 min, 1 h, 3 h, 6 h, 12 h). An endpoint that keeps failing for days is
    turned off and the

    organization's admins get an email. `data.demo` is the demo as it is when
    the event is sent.


    ## Errors

    Every error has the same shape: `{"error": {"code", "message",
    "details"?}}`. Codes:

    `invalid_request` 400, `unauthorized` 401, `paid_plan_required` 402,
    `limit_reached` 402 (with

    `details.limit_code`), `forbidden` 403, `not_found` 404, `conflict` 409,
    `gone` 410,

    `needs_answers` / `not_feasible` 422, `rate_limited` 429 (`Retry-After`),
    `unavailable` 503.

    Rate limits: 300/minute requests per key, 20/minute demo checks or
    creations.
  contact:
    name: Demosmith
    url: https://demosmith.ai
servers:
  - url: https://platform.demosmith.ai/v1
security: []
tags:
  - name: Account
  - name: Demos
  - name: Webhooks
  - name: Webhook events
paths:
  /demos/{demo_id}:
    get:
      tags:
        - Demos
      summary: Get a demo
      operationId: getDemo
      parameters:
        - name: demo_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Demo'
              example:
                id: 5b9e3c7a-2f41-4c8e-9a51-7d0b6e2f1c34
                object: demo
                status: completed
                stage: null
                progress:
                  percent: 100
                  eta_seconds: null
                queue: null
                title: Booking a meeting on Cal.com
                url: https://cal.com
                task: >-
                  Show how to book a 30-minute meeting from a public booking
                  page
                language: en-US
                input_request: null
                video:
                  url: >-
                    https://media.example.com/renders/5b9e3c7a-2f41-4c8e-9a51-7d0b6e2f1c34.mp4?signature=…
                  download_url: >-
                    https://media.example.com/renders/5b9e3c7a-2f41-4c8e-9a51-7d0b6e2f1c34.mp4?download=1&signature=…
                  expires_at: '2026-11-07T14:12:00Z'
                  duration_seconds: 63.4
                  thumbnail_url: >-
                    https://media.example.com/renders/5b9e3c7a-2f41-4c8e-9a51-7d0b6e2f1c34.jpg?signature=…
                failure: null
                app_url: >-
                  https://app.demosmith.ai/demos/5b9e3c7a-2f41-4c8e-9a51-7d0b6e2f1c34
                source: api
                metadata:
                  crm_account: acct_123
                check_again_in_seconds: 0
                created_at: '2026-11-07T11:58:40Z'
                updated_at: '2026-11-07T12:12:00Z'
                finished_at: '2026-11-07T12:12:00Z'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Paid plan required, or a plan limit reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - apiKey: []
components:
  schemas:
    Demo:
      type: object
      required:
        - id
        - object
        - status
      properties:
        id:
          type: string
          format: uuid
        object:
          type: string
          const: demo
        status:
          type: string
          enum:
            - canceled
            - completed
            - failed
            - in_progress
            - input_required
            - queued
        stage:
          type:
            - string
            - 'null'
          enum:
            - analyzing
            - editing
            - narrating
            - recording
            - rendering
            - null
        progress:
          type: object
          properties:
            percent:
              type: number
            eta_seconds:
              type:
                - integer
                - 'null'
        queue:
          type:
            - object
            - 'null'
          properties:
            position:
              type:
                - integer
                - 'null'
            total:
              type:
                - integer
                - 'null'
        title:
          type:
            - string
            - 'null'
        url:
          type: string
          format: uri
        task:
          type: string
        language:
          type:
            - string
            - 'null'
        input_request:
          oneOf:
            - $ref: '#/components/schemas/InputRequest'
            - type: 'null'
        video:
          oneOf:
            - $ref: '#/components/schemas/Video'
            - type: 'null'
        failure:
          type:
            - object
            - 'null'
          properties:
            message:
              type: string
        app_url:
          type: string
          format: uri
        source:
          type: string
          enum:
            - api
            - mcp
            - web
        metadata:
          type: object
          additionalProperties:
            type: string
        check_again_in_seconds:
          type: integer
          description: Wait at least this long before polling again. 0 when finished.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        finished_at:
          type:
            - string
            - 'null'
          format: date-time
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              examples:
                - needs_answers
            message:
              type: string
            details:
              type: object
              additionalProperties: true
    InputRequest:
      type: object
      description: A question the recorder is waiting on.
      properties:
        id:
          type: string
          format: uuid
        kind:
          type: string
          enum:
            - confirmation
            - login
            - question
            - verification_code
        question:
          type: string
        suggestions:
          type: array
          items:
            type: string
        expires_at:
          type: string
          format: date-time
        answer_url:
          type: string
          format: uri
          description: The demo page in the app, where a person can answer securely.
    Video:
      type: object
      properties:
        url:
          type: string
          format: uri
          description: Plays in a browser. Expires after 2 hours.
        download_url:
          type: string
          format: uri
          description: Downloads as an .mp4. Expires after 2 hours.
        expires_at:
          type: string
          format: date-time
        duration_seconds:
          type:
            - number
            - 'null'
        thumbnail_url:
          type:
            - string
            - 'null'
          format: uri
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: dsk_live_…
      description: An API key from the Developers page.

````

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