openapi: 3.0.0
info:
  description: Descript API documentation.
  version: '1.2'
  title: Descript API
  x-logo:
    url: assets/descript-logo.svg
    altText: Descript
  license:
    name: Proprietary
    url: https://www.descript.com/terms
servers:
  - url: https://descriptapi.com/v1
tags:
  - name: Getting started
    description: "> **Early Access:** These APIs are still under active development, and may change and evolve over time. We're thankful for your input, and excited to build with you.\n\nThe Descript API lets you programmatically create projects, import media, and edit your projects — all without opening the app.\n\nTo learn more, visit [descript.com/api](https://descript.com/api).\n\n## Create an API token\n\n1. In Descript, open **Settings** and select **API tokens** from the sidebar. Then click **Create token**.\n\n![Navigate to Settings > API tokens and click Create token](assets/token1.png)\n\n2. Give your token a name and select the Drive it should be associated with. Click **Create token**.\n\n<img src=\"assets/token2.png\" alt=\"Name your token and select a Drive\" width=\"500\" />\n\n3. Copy your token and store it in a safe place. You won't be able to view it again. If you lose it, you'll need to generate a new one.\n\n<img src=\"assets/token3.png\" alt=\"Copy and save your API token\" width=\"500\" />\n\n> **Warning:** Treat your API token like a password. Anyone with your token can make API requests on your behalf using your account permissions. Never share your token publicly or commit it to source control.\n\nInclude the token as a Bearer token in the `Authorization` header of your API requests.\n\n## Import media into a new project\n\nYou can create a new project, import media, and place the media into a composition all in one API request using the [import endpoint](#operation/importProjectMedia). This step also transcribes and processes the media so that it's ready for you or the agent to edit.\n\nTo import files, pass in public or pre-signed URIs. Currently, the API does not support uploading a file directly. To test the API with an example file, use the demo video included in the sample request below.\n\nImporting and processing is an asynchronous job, so the response payload will contain a `job_id` for you to [query the status of the job](#operation/getJob) and information about the newly created project. Note that `project_id` and `project_url` are returned immediately alongside `job_id`, but opening the project in Descript will not always show the API's processing state in real time. To prevent unintended changes, we recommend that you do not make any changes to the project until the job has stopped.\n\n\n\n**Request**\n\n```bash\ncurl -X POST https://descriptapi.com/v1/jobs/import/project_media \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"project_name\": \"My First Video\",\n    \"add_media\": {\n      \"demo.mp4\": {\n        \"url\": \"https://test-files.descriptapi.com/demo-video.mp4\"\n      }\n    },\n    \"add_compositions\": [\n      {\n        \"name\": \"Demo Video\",\n        \"clips\": [\n          { \"media\": \"demo.mp4\" }\n        ]\n      }\n    ]\n  }'\n```\n\n**Response**\n\n```json\n{\n  \"job_id\": \"project-media-import-9d635d5b\",\n  \"drive_id\": \"c9c5c47e\",\n  \"project_id\": \"e2f89ce6\",\n  \"project_url\": \"https://web.descript.com/e2f89ce6\"\n}\n```\n\n## Check for import completion\n\nPoll the [job status endpoint](#operation/getJob) using the `job_id` from the last step to check whether the import job is finished processing. When it is, you'll see `job_state: \"stopped\"`. You can then check the `results` object to see its full results.\n\nYou can also pass in a `callback_url` as a part of the first import request, and we'll ping you when the job has stopped with the same response payload.\n\n**Request**\n\n```bash\ncurl https://descriptapi.com/v1/jobs/project-media-import-9d635d5b \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\"\n```\n\n**Response**\n\n```json\n{\n  \"job_id\": \"project-media-import-9d635d5b\",\n  \"job_type\": \"import/project_media\",\n  \"job_state\": \"stopped\",\n  \"project_id\": \"e2f89ce6\",\n  \"project_url\": \"https://web.descript.com/e2f89ce6\",\n  \"result\": {\n    \"status\": \"success\",\n    \"media_status\": {\n      \"main.mp4\": {\n        \"status\": \"success\",\n        \"duration_seconds\": 69.477006\n      }\n    },\n    \"created_compositions\": [\n      { \"id\": \"f8e5088a-4d53-4aab-9d4f-c6624b7d7622\", \"name\": \"Demo Video\" }\n    ]\n  }\n}\n```\n\n## Prompt for edits with Agent Underlord\n\nOnce your media is imported, you can use the [agent edit endpoint](#operation/agentEditJob) to prompt Underlord for edits, just as you would in the app. Because it's an API, conversation and follow up questions aren't practical. So we recommend framing your edits as a one-shot prompt with all the information the agent needs.\n\nEditing can take some time, so the response also returns a `job_id` that you can use to [check the status of the job](#operation/getJob). You can also pass in a `callback_url` as a part of an agent request, and we'll ping you when the job has stopped.\n\n**Request**\n\n```bash\ncurl -X POST https://descriptapi.com/v1/jobs/agent \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"project_id\": \"e2f89ce6\",\n    \"prompt\": \"Add studio sound and captions\"\n  }'\n```\n\n**Response**\n\n```json\n{\n  \"job_id\": \"project-agent-edit-e2f89ce6\",\n  \"drive_id\": \"c9c5c47e\",\n  \"project_id\": \"e2f89ce6\",\n  \"project_url\": \"https://web.descript.com/e2f89ce6\"\n}\n```\n\n## Wait for the agent to complete its job\n\nPoll the [job status endpoint](#operation/getJob) using the `job_id`. When the agent job completes successfully, the response includes a summary of what it accomplished (see the `result.agent_response` field). Use the project URL to open the project in Descript and review Underlord's changes.\n\n**Request**\n\n```bash\ncurl https://descriptapi.com/v1/jobs/project-agent-edit-e2f89ce6 \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\"\n```\n\nOnce the agent job is successfully complete, you’ll see a response from the agent with a brief summary of what it accomplished. You can then use the project url to review its changes directly in Descript.\n\n**Response**\n\n```json\n{\n\t\"job_id\":\"project-agent-edit-e2f89ce6\",\n\t\"job_type\":\"agent\",\n  \"project_id\":\"YOUR_PROJECT_ID\",\n\t\"project_url\":\"https://web.descript.com/e2f89ce6\",\n\t\"job_state\":\"stopped\",\n\t\"created_at\":\"2026-02-09T05:42:27.554Z\",\n\t\"stopped_at\":\"2026-02-09T05:43:15.296Z\",\n\t\"drive_id\":\"1df135a5-dc4a-4dc3-8f7d-681cfbe961e4\",\n\t\"result\":{\n\t\t\"status\":\"success\",\n    \"agent_response\":\"Done! I've applied Studio Sound to enhance your audio quality and added classic karaoke-style captions to your video.\",\n\t\t\"project_changed\":true,\n\t\t\"media_seconds_used\":0,\n\t\t\"ai_credits_used\":32\n  }\n}\n```\n"
  - name: Using the CLI
    description: |
      The CLI wraps the API into a simple to use command line tool with interactive flows for setting up authentication, importing, and prompting the agent. It also has built-in polling for job completion.

      ## Requirements

      Before installing the CLI, you'll need **Node.js 24 or higher**. Visit [nodejs.org](https://nodejs.org/) to download and install the latest LTS version for your operating system.

      ## Install and set up

      First, install the latest version of the CLI using npm.

      ```bash
      npm install -g @descript/platform-cli@latest
      ```

      Next, configure the CLI with your API key.

      ```bash
      descript-api config set api-key
      ```

      ![Setting up the CLI](assets/cli-set-up.gif)


      ## Import media

      Use the `import` command to create a project by passing a project name and the link to any media you want to upload, or run `descript-api import` for interactive mode. The CLI shows live progress and outputs the project ID when done.

      ```bash
      descript-api import \
        --name "My First Project" \
        --media "https://test-files.descriptapi.com/demo-video.mp4"
      ```

      ![Interactive CLI import](assets/cli-import.gif)

      ## Use the agent

      Use the `agent` command to edit a project by passing in the project id and an Underlord prompt.

      ```bash
      descript-api agent \
        --project-id YOUR_PROJECT_ID \
        --prompt "Remove filler words and add Studio Sound to all clips"
      ```

      You can also ask Underlord create a new project from a prompt alone by writing the script for you!

      ```bash
      descript-api edit --new \
        --prompt "Write a script about how to make great coffee"
      ```

      ## All commands

      Run `descript-api help` to see the full list of available commands and options.
  - name: API Endpoints
    description: Import media, edit projects with AI, and query jobs and projects.
  - name: Authentication
    description: |
      The Descript API uses personal API tokens to authenticate requests. Tokens are scoped to a specific Drive and inherit your permissions on that Drive.

      To create a token, see the [Getting Started](#section/Getting-started/Create-an-API-token) guide.

      > **Warning:** Treat your API token like a password. Anyone with your token can make API requests on your behalf using your account permissions. Never share your token publicly or commit it to source control.

      ## Using your token

      Include the token as a Bearer token in the `Authorization` header of your API requests.

      **Example**

      ```bash
      curl -H "Authorization: Bearer YOUR_API_TOKEN" https://descriptapi.com/v1/status
      ```
  - name: Rate Limiting
    description: |
      The Descript API implements rate limiting to ensure fair usage and protect service availability.
      When you exceed the rate limit, the API returns a `429 Too Many Requests` response.

      ## Rate Limit Headers

      When a rate limit is exceeded, the response includes the following headers:

      | Header | Description |
      |--------|-------------|
      | `Retry-After` | Number of seconds to wait before retrying the request |
      | `X-RateLimit-Remaining` | Number of requests remaining in the current window |
      | `X-RateLimit-Consumed` | Number of requests consumed in the current window |

      ## Handling Rate Limits

      When you receive a `429` response, use the `Retry-After` header to determine how long to wait before retrying.
      This approach is more efficient than using fixed delays or exponential backoff alone.
  - name: Edit in Descript
    description: |
      > **Note:** The Edit in Descript integration requires contacting Descript for access. [Reach out to us](https://descript.com/api) to get started.

      Edit in Descript API enables partners to give their users the ability to transfer audio or video content to Descript for editing.

      Edit in Descript buttons work by generating one-time use, public Import URLs to the Descript import UI that users
      can be automatically sent to. On that page, they can make a few simple selections before kicking off a Partner cloud
      storage to Descript cloud storage transfer. This will redirect them to a Descript Project ready for editing.

      Partners can initiate the request by securely sending an information schema backend-to-backend to the Descript API
      using a token, in exchange for the Import URL to redirect the user. Partners do not need to store this schema, as
      Descript will do so and use it to start fetching the files when the user confirms the action

      1. When a user clicks `Edit in Descript`, partner's backend service makes POST request to:
          `https://descriptapi.com/v1/edit_in_descript/schema` with an authorization bearer token header and JSON schema body
      2. Descript responds with either an Import URL or an error
      3. Partner redirects the user's browser to the URL returned in step 2 or display an error message and link to help documentation

      ### Partner User Experience
      Some guidelines for partners as you consider this integration:
      * We recommend placing the `Edit in Descript` option next to your download options
        * If you offer multiple download options, such as combined vs. split audio/video files, we recommend placing
      this integration clearly in context with each option, or only the supported option, to help users understand
      what will be exported.
        * Each time you request an import link, a new one is generated. Import links expire after 3 hours. After using an
      import link, the only way to find an imported Project again is in Descript.
        * If an import link has expired or the contents of the schema has changed, please request a new import link with
      the updated schema. This will create a new Descript Project when used.
      * We will provide Descript-branded assets to fit your proposed placement of the `Edit in Descript` CTA and ask
      that you don't edit the assets beyond what we provide. We are happy to work with you on getting you the right
      assets for your placement.
      * Partners should provide error-handling for the POST request, at minimum displaying a generic error message and
      linking to a help article (we can provide a link for this if you prefer).
      * Progress will be conveyed to the user in the Descript side of the user experience.

      ### Descript User Experience
      When users are directed to a Descript Import URL, they'll be asked to either create an account or login in order
      to proceed.

      Next, they will be presented with a few options about how they'd like to import the data, such as where the new
      Descript Project should be created.

      They'll then be redirected to the Project, where they can monitor the progress of the import and start editing.
  - name: Export from Descript
    description: |
      Users of Descript currently have three options to export their edited content. They can export files in various
      formats, share a Descript link, or use our [one-click cloud export](https://help.descript.com/hc/en-us/articles/360043869551-Becoming-a-Supported-Content-Hosting-Partner)
      to publish directly to a partner.

      ### Roundtrip Metadata
      If Project data previously came from a partner via an Edit in Descript schema then any Descript Export pages
      will include `<meta/>` tags which contains the `partner_drive_id` and `source_id` provided when originally
      importing into Descript. This allows partners to deduplicate data returning back to partner systems after
      editing in Descript. Both partner and source properties are included on all public Descript Export pages.

      ```
      <meta property="descript:partner" content="9121bf3a-60fe-4a31-ad59-ed32df610cc3" />
      <meta property="descript:source" content="409148bd-81aa-4af6-a9c3-29b761506f3a" />
      ```
paths:
  /jobs/import/project_media:
    post:
      tags:
        - API Endpoints
      summary: Import media and sequences
      security:
        - bearerAuth: []
      description: "Import media files into a new or existing project and create compositions.\n\nThis endpoint can:\n- Create a new project if `project_id` is not provided\n- Import media files from URLs\n- Create multitrack sequences\n- Create compositions (timelines) from existing or new media in the project\n- Trigger transcription and other background processing tasks\n\n### Media URL requirements\n- URLs must be accessible by Descript servers\n- URLs must support HTTP Range requests\n- Recommended to sign URLs for 12-48 hours to reduce chance of failure\n- [Supported file types](https://help.descript.com/hc/en-us/articles/10164098416909-Supported-file-types)\n\n### Async Operations\n\nImports\_run in the background and return a `job_id`. Monitor progress via the [GET /jobs/{job_id}](#operation/getJob) endpoint.\n\n### Dynamic webhook\n\nIf `callback_url` is provided, Descript will POST the job status to that URL when the job finishes (successfully or not).\n\nThe payload will match the format returned by [GET /jobs/{job_id}](#operation/getJob).\n"
      operationId: importProjectMedia
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: |
                Request to import media into a project and optionally create compositions.
                This operation will:
                - Create a new project if project_id is not provided (using the drive associated with the personal token)
                - Import media files from URLs or create multitrack sequences
                - Optionally create one or more compositions
                - Trigger transcription and other background processing
              properties:
                project_id:
                  type: string
                  format: uuid
                  description: |
                    **[Work in progress]** Importing into an existing project is not yet supported. Currently, a new project is always created.

                    Existing project ID to import media into. If not provided, a new project will be created.
                    When importing into an existing project, media filenames must not conflict with existing files.
                  example: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                project_name:
                  type: string
                  description: Name for the new project. Only used when project_id is not provided.
                  example: Marketing Video
                team_access:
                  type: string
                  description: |
                    Access level for drive members. Only applicable when creating a new project
                    (when project_id is not provided). Defaults to `none` if not specified.
                    - edit: Users can edit the project
                    - comment: Users can view and comment but not edit
                    - view: Users can view but not comment or edit
                    - none: No shared access (private to owner)
                  enum:
                    - edit
                    - comment
                    - view
                    - none
                  default: none
                  example: edit
                add_media:
                  type: object
                  description: |
                    Map of media reference IDs (display names with optional folder paths) to media import items.
                    Keys are the display names that will appear in the project (e.g., "Misc/intro.mp4" or "demo.mp4").
                    Values define how to import each media item (URL import or multitrack sequence).
                  additionalProperties:
                    type: object
                    description: |
                      Defines how to import a single media item. Can be either a URL import or a multitrack sequence.
                    oneOf:
                      - type: object
                        title: URL Import
                        description: Import media from a URL
                        required:
                          - url
                        properties:
                          url:
                            type: string
                            format: uri
                            description: |
                              URL to import media from. Must be accessible by Descript servers and support Range requests.
                              Recommended to sign URLs for 12-48 hours to reduce chance of failure.
                            example: https://example.com/intro.mp4
                          language:
                            type: string
                            description: |
                              **[Work in progress]** This property is not yet supported and will be ignored if provided. Language is currently auto-detected.

                              ISO 639-1 language code for transcription (e.g., "en", "es", "fr").
                              If not specified, language is auto-detected from the audio.
                            example: en
                        additionalProperties: false
                      - type: object
                        title: Multitrack Sequence
                        description: Create a multitrack sequence from multiple media files
                        required:
                          - tracks
                        properties:
                          tracks:
                            type: array
                            description: Array of tracks to combine into a multitrack sequence
                            minItems: 1
                            items:
                              type: object
                              required:
                                - media
                              properties:
                                media:
                                  type: string
                                  description: Media reference ID (display name) of the media to include in this track
                                  example: Recordings/camera1.mp4
                                offset:
                                  type: number
                                  format: float
                                  description: Optional time offset in seconds for syncing this track
                                  example: 50
                                  default: 0
                              additionalProperties: false
                        additionalProperties: false
                  example:
                    Misc/intro.mp4:
                      url: https://example.com/intro.mp4
                    demo.mp4:
                      url: https://example.com/demo.mp4
                    Multicam_Track:
                      tracks:
                        - media: Recordings/camera1.mp4
                          offset: 0
                        - media: Recordings/camera2.mp4
                          offset: 50
                add_compositions:
                  type: array
                  description: Optional list of compositions to create in the project
                  items:
                    type: object
                    description: Defines a composition to create in the project
                    properties:
                      name:
                        type: string
                        description: Name of the composition. If not provided, uses default naming.
                        example: Rough Cut
                      width:
                        type: integer
                        description: Width of the composition in pixels
                        example: 1920
                        default: 1920
                      height:
                        type: integer
                        description: Height of the composition in pixels
                        example: 1080
                        default: 1080
                      fps:
                        type: number
                        description: |
                          **[Work in progress]** This property is not yet supported and will be ignored if provided.

                          Frame rate for the composition in frames per second.
                          Common values: 24, 25, 29.97, 30, 60.
                        default: 30
                        example: 30
                      clips:
                        type: array
                        description: Ordered list of clips to include in the composition
                        items:
                          type: object
                          required:
                            - media
                          properties:
                            media:
                              type: string
                              description: Media reference ID (display name) of the media to add as a clip
                              example: Misc/intro.mp4
                          additionalProperties: false
                    required:
                      - clips
                    additionalProperties: false
                callback_url:
                  type: string
                  format: uri
                  description: |
                    Optional webhook URL to call when the job completes or fails.
                    Descript will POST the job status (same format as [GET /jobs/{job_id}](#operation/getJob)) to this URL.
                  example: https://example.com/webhooks/descript/job_callback
              additionalProperties: false
            examples:
              create_with_composition:
                summary: Create project with initial composition
                description: Most common use case for seeding a project with a simple composition
                value:
                  project_name: Marketing Video
                  add_media:
                    Misc/intro.mp4:
                      url: https://example.com/intro.mp4
                    demo.mp4:
                      url: https://example.com/demo.mp4
                    Misc/outro.mp4:
                      url: https://example.com/outro.mp4
                  add_compositions:
                    - name: Rough Cut
                      clips:
                        - media: Misc/intro.mp4
                        - media: demo.mp4
                        - media: Misc/outro.mp4
              import_only:
                summary: Import media without composition
                description: Import files for later composition creation
                value:
                  project_name: Video Project
                  add_media:
                    Assets/intro.mp4:
                      url: https://example.com/intro.mp4
                    Assets/logo.png:
                      url: https://example.com/logo.png
              multitrack_sequence:
                summary: Create multitrack sequence
                description: Combine multiple tracks with time offsets
                value:
                  project_name: Interview Edit
                  add_media:
                    Misc/intro.mp4:
                      url: https://example.com/intro.mp4
                    Recordings/camera1.mp4:
                      url: https://example.com/camera1.mp4
                    Recordings/camera2.mp4:
                      url: https://example.com/camera2.mp4
                    Multicam_Track:
                      tracks:
                        - media: Recordings/camera1.mp4
                          offset: 0
                        - media: Recordings/camera2.mp4
                          offset: 50
                  add_compositions:
                    - name: Rough Cut
                      width: 1920
                      height: 1080
                      clips:
                        - media: Misc/intro.mp4
                        - media: Multicam_Track
        description: Media import and project creation request
        required: true
      responses:
        '201':
          description: Import job created successfully
          content:
            application/json:
              schema:
                type: object
                description: Response returned when creating an import job
                properties:
                  job_id:
                    type: string
                    format: uuid
                    description: Unique identifier for the job
                    example: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                  drive_id:
                    type: string
                    format: uuid
                    description: Drive ID where the project is located
                    example: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                  project_id:
                    type: string
                    format: uuid
                    description: Project ID (newly created or existing)
                    example: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                  project_url:
                    type: string
                    format: uri
                    description: URL to access the project in Descript web app
                    example: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                required:
                  - job_id
                  - drive_id
                  - project_id
                  - project_url
        '400':
          description: |
            Invalid input:
            - Malformed request body
            - Invalid media URLs
            - URLs not accessible or don't support Range requests
            - Media filename conflicts with existing files (when importing to existing project)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error400'
              examples:
                invalid_url:
                  summary: Invalid media URL
                  value:
                    error: invalid_input
                    message: Invalid media URL format
                url_not_accessible:
                  summary: URL not accessible
                  value:
                    error: invalid_input
                    message: Media URL is not accessible or does not support Range requests
                filename_conflict:
                  summary: Filename conflict
                  value:
                    error: invalid_input
                    message: Media filename conflicts with existing files in the project
        '401':
          description: Unauthorized - missing or invalid authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
              examples:
                unauthorized:
                  summary: Missing authentication token
                  value:
                    error: unauthorized
                    message: Missing or invalid authentication token
        '402':
          description: Payment Required - insufficient media minutes to start the job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error402'
              examples:
                insufficient_minutes:
                  summary: Insufficient media minutes
                  value:
                    error: payment_required
                    message: Insufficient media minutes to start the job (300 minutes required, 50 available)
        '403':
          description: Forbidden - user does not have access to this resource
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error403'
              examples:
                forbidden:
                  summary: No access to drive or project
                  value:
                    error: forbidden
                    message: User does not have access to this drive or project
        '404':
          description: |
            Not found:
            - Drive doesn't exist
            - Project doesn't exist (when project_id is provided)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
              examples:
                project_not_found:
                  summary: Project not found
                  value:
                    error: not_found
                    message: Project not found
                drive_not_found:
                  summary: Drive not found
                  value:
                    error: not_found
                    message: Drive not found
        '429':
          $ref: '#/components/responses/Error429Response'
  /jobs/agent:
    post:
      tags:
        - API Endpoints
      summary: Agent edit
      security:
        - bearerAuth: []
      description: |
        Use a background agent to create and edit projects using a natural language prompt.

        - **Edit existing project**: Provide a `project_id` to edit an existing project
        - **Create new project**: Provide a `project_name` instead of `project_id` to create a new project

        ### Common use cases
        - Create new content: "create a 30-second video about cooking tips"
        - Apply audio effects: "add studio sound to every clip"
        - Remove filler words: "remove all filler words from the transcript"
        - Create highlights: "create a 30-second highlight reel"
        - Content editing: "remove the section from 1:30 to 2:15"

        ### Async Operations

        Agent edits run in the background and return a `job_id`. Monitor progress via the [GET /jobs/{job_id}](#operation/getJob) endpoint.

        ### Dynamic webhook

        If `callback_url` is provided, Descript will POST the job status to that URL when the job completes or fails.
        The payload will match the format returned by [GET /jobs/{job_id}](#operation/getJob).
      operationId: agentEditJob
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: |
                Request to run Agent edit.
                The agent will interpret the prompt and either edit an existing project or create a new one.
                You must provide exactly one of `project_id` or `project_name`.
              properties:
                project_id:
                  type: string
                  format: uuid
                  description: |
                    The ID of an existing project to edit. Mutually exclusive with `project_name`.
                  example: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                project_name:
                  type: string
                  description: |
                    Name for creating a new project. Mutually exclusive with `project_id`.
                  example: My New Project
                composition_id:
                  type: string
                  format: uuid
                  description: |
                    **[Work in progress]** This property is accepted but not yet functional. It will be ignored.

                    Optional composition ID within the project to edit.
                  example: 39677a40-1c43-4c36-8449-46cfbc4de2b5
                model:
                  type: string
                  description: |
                    AI model to use for editing. Defaults to the default model.
                prompt:
                  type: string
                  description: |
                    Natural language instruction for the agent to execute.
                    Examples: "add studio sound to every clip", "remove all filler words", "create a 30-second highlight reel"
                  example: add studio sound to every clip
                team_access:
                  type: string
                  enum:
                    - edit
                    - comment
                    - view
                    - none
                  description: |
                    Access level for team members when creating a new project.
                    Only applicable when `project_name` is provided (not when using `project_id`).
                    Defaults to `none` if not specified.
                callback_url:
                  type: string
                  format: uri
                  description: |
                    Optional webhook URL to call when the job completes or fails.
                    Descript will POST the job status (same format as [GET /jobs/{job_id}](#operation/getJob)) to this URL.
                  example: https://example.com/webhooks/descript/job_callback
              required:
                - prompt
              additionalProperties: false
            examples:
              create_new_project:
                summary: Create a new project
                value:
                  project_name: Cooking Tips Video
                  prompt: create a 30-second video about cooking tips with background music
              add_studio_sound:
                summary: Add Studio Sound effect
                value:
                  project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                  model: haiku-4.5
                  prompt: add studio sound to every clip
              remove_filler_words:
                summary: Remove filler words
                value:
                  project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                  prompt: remove all filler words
              create_highlight:
                summary: Create highlight reel
                value:
                  project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                  composition_id: 39677a40-1c43-4c36-8449-46cfbc4de2b5
                  prompt: create a 30-second highlight reel with the best moments
              with_callback:
                summary: Agent job with webhook callback
                value:
                  project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                  prompt: add studio sound to every clip
                  callback_url: https://example.com/webhooks/descript/job_callback
        description: AI agent request
        required: true
      responses:
        '201':
          description: Agent edit job created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  job_id:
                    type: string
                    format: uuid
                    description: Unique identifier for the Agent edit job
                    example: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                  drive_id:
                    type: string
                    format: uuid
                    description: Drive ID where the project is located
                    example: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                  project_id:
                    type: string
                    format: uuid
                    description: The project ID (existing or newly created)
                    example: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                  project_url:
                    type: string
                    format: uri
                    description: URL to access the project in Descript web app
                    example: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                required:
                  - job_id
                  - drive_id
                  - project_id
                  - project_url
        '400':
          description: |
            Invalid input:
            - Malformed request body
            - Invalid project_id or composition_id
            - Empty or invalid prompt
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error400'
              examples:
                empty_prompt:
                  summary: Empty prompt
                  value:
                    error: invalid_input
                    message: Prompt cannot be empty
                invalid_project:
                  summary: Invalid project ID
                  value:
                    error: invalid_input
                    message: Invalid project_id format
        '401':
          description: Unauthorized - missing or invalid authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
              examples:
                unauthorized:
                  summary: Missing authentication token
                  value:
                    error: unauthorized
                    message: Missing or invalid authentication token
        '402':
          description: Payment Required - insufficient AI credits to start the job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error402'
              examples:
                insufficient_credits:
                  summary: Insufficient AI credits
                  value:
                    error: payment_required
                    message: Insufficient AI credits to start the job (100 credits required, 25 available)
        '404':
          description: |
            Not found:
            - Project doesn't exist
            - Composition doesn't exist (when composition_id is provided)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
              examples:
                project_not_found:
                  summary: Project not found
                  value:
                    error: not_found
                    message: Project not found
                composition_not_found:
                  summary: Composition not found
                  value:
                    error: not_found
                    message: Composition not found
        '429':
          $ref: '#/components/responses/Error429Response'
  /jobs:
    get:
      tags:
        - API Endpoints
      summary: List jobs
      description: |
        List recent jobs with optional filtering by project or job type.

        By default, jobs created within the last 7 days are returned. Use `created_after` and
        `created_before` to customize the time range. The maximum lookback is 30 days.

        Results are paginated. Use the `cursor` from the response `pagination.next_cursor` to
        fetch subsequent pages.

        Query parameters allow you to filter the results:
        * Filter by `project_id` to see all jobs for a project
        * Filter by `type` to see specific job types (import/project_media, agent)
      operationId: listJobs
      security:
        - bearerAuth: []
      parameters:
        - in: query
          name: project_id
          description: Filter by project ID
          required: false
          schema:
            type: string
            format: uuid
        - in: query
          name: type
          description: Filter by job type
          required: false
          schema:
            type: string
            enum:
              - import/project_media
              - agent
        - in: query
          name: cursor
          description: Cursor for the next page of results, obtained from `pagination.next_cursor` in a previous response
          required: false
          schema:
            type: string
        - in: query
          name: limit
          description: Number of items per page (1-100). Defaults to 20.
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - in: query
          name: created_after
          description: 'Filter jobs created after this timestamp (ISO 8601). Default: 7 days ago. Oldest allowed: 30 days ago.'
          required: false
          schema:
            type: string
            format: date-time
        - in: query
          name: created_before
          description: 'Filter jobs created before this timestamp (ISO 8601). Default: now.'
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Jobs list retrieved successfully
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/JobStatus'
                  pagination:
                    type: object
                    properties:
                      next_cursor:
                        type: string
                        description: Cursor for the next page of results. Absent if no more results.
              examples:
                mixed_jobs:
                  summary: List of jobs with different types and states
                  value:
                    data:
                      - job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                        job_type: import/project_media
                        job_state: stopped
                        created_at: '2025-11-18T10:30:00Z'
                        stopped_at: '2025-11-18T10:35:00Z'
                        drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                        project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                        project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                        result:
                          status: success
                          media_status:
                            Misc/intro.mp4:
                              status: success
                              duration_seconds: 10.5
                          media_seconds_used: 11
                      - job_id: a1b2c3d4-5678-90ab-cdef-1234567890ab
                        job_type: agent
                        job_state: running
                        created_at: '2025-11-18T11:00:00Z'
                        drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                        project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                        project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                        progress:
                          label: Applying Studio Sound to clip 2...
                          last_update_at: '2025-11-18T11:01:00Z'
                    pagination:
                      next_cursor: YTFiMmMzZDQtNTY3OC05MGFiLWNkZWYtMTIzNDU2Nzg5MGFi
        '401':
          description: Unauthorized - invalid or missing authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
              examples:
                unauthorized:
                  summary: Missing authentication token
                  value:
                    error: unauthorized
                    message: Missing or invalid authentication token
        '429':
          $ref: '#/components/responses/Error429Response'
  /jobs/{job_id}:
    get:
      tags:
        - API Endpoints
      summary: Get job status
      security:
        - bearerAuth: []
      description: |
        Retrieve the status of any job.

        The response format varies based on job type and includes type-specific fields.
      operationId: getJob
      parameters:
        - in: path
          name: job_id
          description: The job ID
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Job status retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobStatus'
              examples:
                import_success:
                  summary: Import job completed successfully
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: import/project_media
                    job_state: stopped
                    created_at: '2025-11-18T10:30:00Z'
                    stopped_at: '2025-11-18T10:35:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    result:
                      status: success
                      media_status:
                        Misc/intro.mp4:
                          status: success
                          duration_seconds: 10.5
                        demo.mp4:
                          status: success
                          duration_seconds: 125
                      media_seconds_used: 136
                      created_compositions:
                        - id: 0171c
                          name: Rough Cut
                import_partial:
                  summary: Import job partially completed
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: import/project_media
                    job_state: stopped
                    created_at: '2025-11-18T10:30:00Z'
                    stopped_at: '2025-11-18T10:35:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    result:
                      status: partial
                      media_status:
                        Misc/intro.mp4:
                          status: success
                          duration_seconds: 10.5
                        demo.mp4:
                          status: success
                          duration_seconds: 125
                        outro.mp4:
                          status: failed
                          error_message: URL is not accessible or does not support Range requests
                      media_seconds_used: 136
                      created_compositions:
                        - id: 0171c
                          name: Rough Cut
                agent_success:
                  summary: Agent job completed successfully
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: agent
                    job_state: stopped
                    created_at: '2025-11-18T10:30:00Z'
                    stopped_at: '2025-11-18T10:32:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    result:
                      status: success
                      agent_response: I added Studio Sound to all 3 clips in your composition
                      project_changed: true
                      media_seconds_used: 0
                      ai_credits_used: 150
                job_running:
                  summary: Job still running
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: import/project_media
                    job_state: running
                    created_at: '2025-11-18T10:30:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                agent_running:
                  summary: Agent job running with progress
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: agent
                    job_state: running
                    created_at: '2025-11-18T10:30:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    progress:
                      label: Applying Studio Sound to clip 2
                      last_update_at: '2025-11-18T10:32:00Z'
                job_failed:
                  summary: Job failed
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: import/project_media
                    job_state: stopped
                    created_at: '2025-11-18T10:30:00Z'
                    stopped_at: '2025-11-18T10:31:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    result:
                      status: error
                      error_message: Failed to download media file from URL
                job_cancelled:
                  summary: Job cancelled
                  value:
                    job_id: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
                    job_type: agent
                    job_state: cancelled
                    created_at: '2025-11-18T10:30:00Z'
                    stopped_at: '2025-11-18T10:31:00Z'
                    drive_id: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
                    project_id: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
                    project_url: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
        '401':
          description: Unauthorized - invalid or missing authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
              examples:
                unauthorized:
                  summary: Missing authentication token
                  value:
                    error: unauthorized
                    message: Missing or invalid authentication token
        '403':
          description: Forbidden - user does not have access to this job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error403'
              examples:
                forbidden:
                  summary: No access to job
                  value:
                    error: forbidden
                    message: User does not have access to this job
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
              examples:
                not_found:
                  summary: Job does not exist
                  value:
                    error: not_found
                    message: Job not found
        '429':
          $ref: '#/components/responses/Error429Response'
    delete:
      tags:
        - API Endpoints
      summary: Cancel job
      description: |
        Cancel a running job.
      operationId: cancelJob
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: job_id
          description: The job ID
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Job cancelled successfully
        '401':
          description: Unauthorized - invalid or missing authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
              examples:
                unauthorized:
                  summary: Missing authentication token
                  value:
                    error: unauthorized
                    message: Missing or invalid authentication token
        '403':
          description: Forbidden - user does not have access to this job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error403'
              examples:
                forbidden:
                  summary: No access to job
                  value:
                    error: forbidden
                    message: User does not have access to this job
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
              examples:
                not_found:
                  summary: Job does not exist
                  value:
                    error: not_found
                    message: Job not found
        '429':
          $ref: '#/components/responses/Error429Response'
  /status:
    get:
      tags:
        - API Endpoints
      summary: Check API status
      security:
        - bearerAuth: []
      description: |
        > **Work in progress** — This endpoint is not yet available and will return an error if called.

        Check API availability and validate authentication token.

        This endpoint can be used to:
        - Verify that your authentication token is valid
        - Check API connectivity without performing any heavy operations

        Returns a success response if the token is valid, or a 401 error if the token is invalid or missing.
      operationId: getStatus
      responses:
        '200':
          description: Token is valid and API is available
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - ok
                    description: API status indicator
                    example: ok
                required:
                  - status
              examples:
                success:
                  summary: Successful status check
                  value:
                    status: ok
        '401':
          description: Unauthorized - missing or invalid authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
              examples:
                unauthorized:
                  summary: Missing authentication token
                  value:
                    error: unauthorized
                    message: Missing or invalid authentication token
  /published_projects/{publishedProjectSlug}:
    get:
      tags:
        - Export from Descript
      summary: Get Published Project Metadata
      description: |
        Retrieve metadata for a published Descript project by its URL slug. This endpoint provides information
        about the published project including title, duration, publisher details, privacy settings, and subtitles.

        This endpoint requires authentication using a personal token and is subject to rate limiting of 1000
        requests per hour per user.
      operationId: getPublishedProjectMetadata
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: publishedProjectSlug
          description: The unique URL slug identifying the published project
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved published project metadata.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishedProjectMetadata'
        '401':
          description: Unauthorized - invalid or missing authentication token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishedProjectPrivateError'
        '403':
          description: Forbidden - user does not have access to this published project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishedProjectForbiddenError'
        '404':
          description: Not found - published project does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishedProjectError'
        '409':
          description: Conflict - published project is in an invalid state (processing or failed).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublishedProjectConflictError'
        '429':
          $ref: '#/components/responses/Error429Response'
  /edit_in_descript/schema:
    post:
      tags:
        - Edit in Descript
      summary: Create Import URL
      description: |
        Create an Import URL by sending a Project schema to Descript API from your service's backend.

        ### Import Schema
        Our import schemas are specified as a minimal JSON list of files which is detailed in full at the bottom of this
        section. At it's smallest, the request body looks like:

        ```
        {
          "partner_drive_id": "162c61d1-6ced-4b25-a622-7dba922983ee",
          "project_schema": {
            "schema_version": "1.0.0",
            "files": [{"uri": "https://descriptusercontent.com/jane.wav?signature=d182bca64bf94a1483d2fd16b579f955"}]
          }
        }
        ```

        ### File Access
        The file paths provided in the schema need to either be public or pre-signed URIs with enough time before
        expiration for failures and retries, we suggest URIs that won't expire for 48 hours. We ask that the files have
        already been saved when the import link is generated to minimize cases where we're waiting for eventually
        consistent storage of files that will never be written. We will, however, wait for eventual consistency of the
        storage layer and retry fetching files before eventually timing out.

        Files must be hosted on preapproved hosts as our import process has an allow list which it checks URIs against.
        Files will be requested with `User-Agent: Descriptbot/1.0` (version may change) for tracking purposes.

        ### Import link expiration
        Import links are no longer valid after a user imports their data once. Viewing an already used import link will
        not allow for importing again and will not provide access to a previously created Descript Project. Partners are
        able to generate a new import link at any time, regardless of if a previous import link has been used.

        The API does not currently provide partners with a link to the Descript Project, though users will be redirected
        to it from Descript's web interface the first time they import files, and can always find the Project in Descript.

        Import links expire after 3 hours and attempting to use an import link after the pre-signed links in the schema
        file have expired will result in an error, so we recommend generating the import link after the user has clicked
        the Edit in Descript button.

        ### Supported media specification
        We recommend sending the highest quality, uncompressed versions of files available to you. If you have multiple
        tracks, we recommend prioritizing sending us the full multi-track sequence over a combined file.

        * Audio: WAV, FLAC, AAC, MP3
        * Video: h264, HEVC (container: MOV, MP4)
      operationId: postEditInDescriptSchema
      security:
        - bearerAuth: []
      requestBody:
        description: Edit in Descript schema POST body.
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EditInDescriptSchemaPostBody'
      responses:
        '201':
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EditInDescriptSchemaPostResponse'
        '400':
          description: Invalid input.
        '403':
          description: Associated drive does not have Edit in Descript permissions.
        '429':
          $ref: '#/components/responses/Error429Response'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Personal API token created in Descript Settings → API Tokens. See the Authentication section for details.
  schemas:
    Error400:
      type: object
      properties:
        error:
          type: string
          example: invalid_input
        message:
          type: string
          example: Invalid request body
      required:
        - error
        - message
    Error401:
      type: object
      properties:
        error:
          type: string
          example: unauthorized
        message:
          type: string
          example: Missing or invalid authentication token
      required:
        - error
        - message
    Error402:
      type: object
      properties:
        error:
          type: string
          example: payment_required
        message:
          type: string
          example: Insufficient media minutes to start the job
      required:
        - error
        - message
    Error403:
      type: object
      properties:
        error:
          type: string
          example: forbidden
        message:
          type: string
          example: User does not have access to this resource
      required:
        - error
        - message
    Error404:
      type: object
      properties:
        error:
          type: string
          example: not_found
        message:
          type: string
          example: Resource not found
      required:
        - error
        - message
    Error429:
      description: |
        Rate limit exceeded response. When this error is returned, the response includes headers
        to help you implement proper retry logic:
        - `Retry-After`: Number of seconds to wait before retrying
        - `X-RateLimit-Remaining`: Requests remaining in current window
        - `X-RateLimit-Consumed`: Requests consumed in current window
      type: object
      properties:
        error:
          type: string
          description: Error code indicating rate limit was exceeded
          example: rate_limit_exceeded
        message:
          type: string
          description: Human-readable error message
          example: Too many requests
      required:
        - error
        - message
    EditInDescriptSchemaPostBody:
      type: object
      properties:
        partner_drive_id:
          type: string
          format: uuid
          description: The drive id associated with the auth token.
          example: aa3b2d8d-e5ca-41c2-8801-683328293fb9
        project_schema:
          type: object
          description: The Project schema
          properties:
            schema_version:
              type: string
              format: string
              description: Schema version id.
              example: 1.0.0
            source_id:
              type: string
              format: string
              description: External source id to be included in Descript export pages, see Export from Descript section for details. This ID is not currently used to deduplicate data coming into Descript, a new Project is created for each import.
              example: 06b3f5bb-68a2-468a-a5d9-df155c1e3588
            files:
              type: array
              description: List of remote files to import into Descript.
              items:
                type: object
                properties:
                  name:
                    type: string
                    format: string
                    description: A name for the file.
                  uri:
                    type: string
                    format: url
                    description: A public/pre-signed uri to the audio or video asset, see supported media specifications section.
                  start_offset:
                    type: object
                    description: The amount of time into the Project's timeline this audio or video file should start at.
                    properties:
                      seconds:
                        type: number
                        description: Float number of seconds into the timeline.
                example:
                  name: Jane's studio recording
                  uri: https://descriptusercontent.com/jane.wav?signature=d182bca64bf94a1483d2fd16b579f955
                  start_offset:
                    seconds: 10
                required:
                  - uri
          required:
            - schema_version
            - files
      required:
        - partner_drive_id
        - project_schema
    EditInDescriptSchemaPostResponse:
      type: object
      properties:
        url:
          type: string
          format: url
          example: https://web.descript.com/import?nonce=6e3625ca-f885-460d-b2e3-e3faac79c788
          description: A url for partners to redirect their user to in order to start the import process—expires after 3 hours.
    PublishedProjectMetadata:
      type: object
      description: Metadata for a successfully published Descript project
      properties:
        project_id:
          type: string
          format: uuid
          description: The unique identifier of the source Descript project
          example: 12345678-1234-5678-1234-567812345678
        publish_type:
          type: string
          enum:
            - audio
            - video
            - audiogram
          description: The type of published project
          example: video
        privacy:
          type: string
          enum:
            - public
            - unlisted
            - private
            - drive
            - password
          description: The access permission level for this published project
          example: unlisted
        metadata:
          type: object
          description: Detailed metadata about the published project
          properties:
            title:
              type: string
              description: The title of the published project
              example: My Video Project
            duration_seconds:
              type: number
              description: Duration of the published content in seconds (rounded to nearest millisecond)
              example: 125.456
            duration_formatted:
              type: string
              description: Human-readable duration in HH:MM:SS format
              example: '00:02:05'
            published_at:
              type: string
              format: date-time
              description: ISO 8601 timestamp of when the project was published
              example: '2025-01-15T10:30:00.000Z'
            published_by:
              type: object
              description: Information about the user who published the project
              properties:
                first_name:
                  type: string
                  description: First name of the publisher
                  example: Jane
                last_name:
                  type: string
                  description: Last name of the publisher
                  example: Doe
        subtitles:
          type: string
          description: Full VTT-formatted subtitle/caption content for the published project
          example: WEBVTT\n\n00:00:00.000 --> 00:00:02.000\nWelcome to my video
      required:
        - project_id
        - publish_type
        - privacy
        - metadata
        - subtitles
    PublishedProjectError:
      type: object
      description: Error response for published project requests
      properties:
        error:
          type: string
          enum:
            - not_found
            - unauthorized
            - forbidden
          description: Error type identifier
          example: not_found
        message:
          type: string
          description: Human-readable error message
          example: Published project not found
      required:
        - error
        - message
    PublishedProjectPrivateError:
      type: object
      description: Error response when published project is private to drive and user is unauthenticated
      properties:
        error:
          type: string
          enum:
            - unauthorized
          description: Error type identifier
          example: unauthorized
        message:
          type: string
          description: Human-readable error message
          example: Private to drive, user must log in to account with access.
    PublishedProjectForbiddenError:
      type: object
      description: Error response when the user does not have access to the published project
      properties:
        error:
          type: string
          enum:
            - forbidden
          description: Error type identifier
          example: forbidden
        message:
          type: string
          description: Human-readable error message
          example: User id 00000000-0000-0000-0000-000000000000 does not have access to this project
    PublishedProjectConflictError:
      type: object
      description: Error response when published project is in an invalid state
      properties:
        error:
          type: string
          enum:
            - conflict
          description: Error type identifier
          example: conflict
        message:
          type: string
          description: Human-readable error message
          example: Published in invalid state
        state:
          type: string
          enum:
            - processing
            - failed
          description: Current state of the published project
          example: processing
      required:
        - error
        - message
        - state
    ImportSuccessResult:
      type: object
      title: ImportSuccessResult
      description: Result when media was imported (fully or partially)
      properties:
        status:
          type: string
          enum:
            - success
            - partial
          description: |
            - success: All media imported successfully
            - partial: Some media imported successfully, some failed
          example: success
        media_status:
          type: object
          description: |
            Status of each media item in the import.
            Keys are the media reference IDs from the request.
          additionalProperties:
            type: object
            description: Status information for a single media import
            properties:
              status:
                type: string
                enum:
                  - success
                  - failed
                description: Status of this individual media import
              duration_seconds:
                type: number
                format: float
                description: Duration of the imported media in seconds (only present for successful imports)
                example: 125.5
              error_message:
                type: string
                description: Error message if the import failed (only present for failed imports)
                example: URL is not accessible or does not support Range requests
            required:
              - status
          example:
            Misc/intro.mp4:
              status: success
              duration_seconds: 10.5
            demo.mp4:
              status: success
              duration_seconds: 125
        media_seconds_used:
          type: integer
          description: Total media seconds consumed by this import
          example: 75
        created_compositions:
          type: array
          description: Compositions created during import
          items:
            type: object
            properties:
              id:
                type: string
                example: 0daabc7a-437a-43eb-b04b-b398d502f393
              name:
                type: string
                example: Rough Cut
      required:
        - status
        - media_status
        - media_seconds_used
    ImportErrorResult:
      type: object
      title: ImportErrorResult
      description: Result when job failed completely
      properties:
        status:
          type: string
          enum:
            - error
          description: Job failed completely
          example: error
        error_message:
          type: string
          description: Human-readable error message
          example: Failed to import media files
        error_code:
          type: string
          description: Machine-readable error code
          example: import_failed
      required:
        - status
        - error_message
    ImportJobStatus:
      type: object
      description: Status of an import job
      properties:
        job_id:
          type: string
          format: uuid
          description: Unique identifier for the job
          example: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
        job_type:
          type: string
          enum:
            - import/project_media
          description: Type of job
        job_state:
          type: string
          enum:
            - queued
            - running
            - stopped
            - cancelled
          description: |
            Current state of the job:
            - queued: Job is waiting to start
            - running: Job is actively processing
            - stopped: Job has finished (check result.status for outcome)
            - cancelled: Job was cancelled by user
          example: stopped
        created_at:
          type: string
          format: date-time
          description: When the job was created
          example: '2025-11-18T10:30:00Z'
        stopped_at:
          type: string
          format: date-time
          description: When the job stopped (only present when job_state is stopped or cancelled)
          example: '2025-11-18T10:35:00Z'
        drive_id:
          type: string
          format: uuid
          description: The drive ID
          example: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
        project_id:
          type: string
          format: uuid
          description: The project ID
          example: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
        project_url:
          type: string
          format: uri
          description: URL to access the project in Descript web app
          example: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
        progress:
          type: object
          description: Progress information for the workflow (only present when job_state is running)
          properties:
            label:
              type: string
              description: Human-readable label describing the current action
              example: Importing media...
            percent:
              type: integer
              description: Percentage of the workflow that has been completed
              example: 50
            last_update_at:
              type: string
              format: date-time
              description: When the progress was last updated
              example: '2025-11-18T10:32:00Z'
          required:
            - label
        result:
          description: Job result (only present when job_state is stopped)
          oneOf:
            - $ref: '#/components/schemas/ImportSuccessResult'
            - $ref: '#/components/schemas/ImportErrorResult'
          discriminator:
            propertyName: status
            mapping:
              success: '#/components/schemas/ImportSuccessResult'
              partial: '#/components/schemas/ImportSuccessResult'
              error: '#/components/schemas/ImportErrorResult'
      required:
        - job_id
        - job_type
        - job_state
        - created_at
        - drive_id
        - project_id
        - project_url
    AgentSuccessResult:
      type: object
      title: AgentSuccessResult
      description: Result when Agent edit completed successfully
      properties:
        status:
          type: string
          enum:
            - success
          description: Indicates successful completion
          example: success
        agent_response:
          type: string
          description: AI response describing what was done
          example: I added Studio Sound to all 3 clips in your composition
        project_changed:
          type: boolean
          description: Whether the agent made modifications to the project
          example: true
        media_seconds_used:
          type: integer
          description: Media minutes (in seconds) consumed by this operation
          example: 34
        ai_credits_used:
          type: integer
          description: AI credits consumed by this operation
          example: 5
      required:
        - status
        - agent_response
        - project_changed
    AgentErrorResult:
      type: object
      title: AgentErrorResult
      description: Result when Agent edit failed
      properties:
        status:
          type: string
          enum:
            - error
          description: Indicates the job failed
          example: error
        error_message:
          type: string
          description: Human-readable error message
          example: AI agent failed to process the request
        error_code:
          type: string
          description: Machine-readable error code
          example: agent_execution_failed
      required:
        - status
        - error_message
    AgentJobStatus:
      type: object
      description: Status of an Agent edit job
      properties:
        job_id:
          type: string
          format: uuid
          description: Unique identifier for the job
          example: 6dc3f30a-58c2-4174-96a6-dc18cf3c7776
        job_type:
          type: string
          enum:
            - agent
          description: Type of job
          example: agent
        job_state:
          type: string
          enum:
            - queued
            - running
            - stopped
            - cancelled
          description: |
            Current state of the job:
            - queued: Job is waiting to start
            - running: Job is actively processing
            - stopped: Job has finished (check result.status for outcome)
            - cancelled: Job was cancelled by user
          example: stopped
        created_at:
          type: string
          format: date-time
          description: When the job was created
          example: '2025-11-18T10:30:00Z'
        stopped_at:
          type: string
          format: date-time
          description: When the job stopped (only present when job_state is stopped or cancelled)
          example: '2025-11-18T10:35:00Z'
        drive_id:
          type: string
          format: uuid
          description: The drive ID
          example: c9c5c47e-158a-49f7-846b-4f6ee2a229a2
        project_id:
          type: string
          format: uuid
          description: The project ID
          example: 9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
        project_url:
          type: string
          format: uri
          description: URL to access the project in Descript web app
          example: https://web.descript.com/9f36ee32-5a2c-47e7-b1a3-94991d3e3ddb
        progress:
          type: object
          description: Progress information for the workflow (only present when job_state is running)
          properties:
            label:
              type: string
              description: Human-readable label describing the current action
              example: Applying Studio Sound to clip 2...
            percent:
              type: integer
              description: Percentage of the workflow that has been completed
              example: 50
            last_update_at:
              type: string
              format: date-time
              description: When the progress was last updated
              example: '2025-11-18T10:32:00Z'
          required:
            - label
        result:
          description: Job result (only present when job_state is stopped)
          oneOf:
            - $ref: '#/components/schemas/AgentSuccessResult'
            - $ref: '#/components/schemas/AgentErrorResult'
          discriminator:
            propertyName: status
            mapping:
              success: '#/components/schemas/AgentSuccessResult'
              error: '#/components/schemas/AgentErrorResult'
      required:
        - job_id
        - job_type
        - job_state
        - created_at
        - drive_id
        - project_id
        - project_url
    JobStatus:
      oneOf:
        - $ref: '#/components/schemas/ImportJobStatus'
        - $ref: '#/components/schemas/AgentJobStatus'
      discriminator:
        propertyName: job_type
        mapping:
          import/project_media: '#/components/schemas/ImportJobStatus'
          agent: '#/components/schemas/AgentJobStatus'
      description: |
        Status of an async job. The response structure varies based on the job type.
        Use the `job_type` field to determine which fields will be present.
  responses:
    Error429Response:
      description: |
        Too many requests - rate limit exceeded.
        Use the `Retry-After` header to determine when to retry.
      headers:
        Retry-After:
          description: Number of seconds to wait before retrying the request
          schema:
            type: integer
          example: 30
        X-RateLimit-Remaining:
          description: Number of requests remaining in the current rate limit window
          schema:
            type: integer
          example: 0
        X-RateLimit-Consumed:
          description: Number of requests consumed in the current rate limit window
          schema:
            type: integer
          example: 100
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error429'
          examples:
            rate_limit:
              summary: Rate limit exceeded
              value:
                error: rate_limit_exceeded
                message: Too many requests. Please try again later.
x-tagGroups:
  - name: Early Access Public API
    tags:
      - Getting started
      - Using the CLI
      - API Endpoints
      - Authentication
      - Rate Limiting
  - name: Partner APIs
    tags:
      - Edit in Descript
      - Export from Descript
