---
title: "Publish project media"
method: POST
path: "/jobs/publish"
tags: ["API Endpoints"]
---

# Publish project media

`POST /jobs/publish`

Publish a project composition to create a shareable link and download the exported file.

Publishes a specific composition from a project, rendering the output as video or audio
at the specified resolution. When the job completes successfully the result contains both:

- `share_url`: a public URL that can be used to view the published content on Descript's share site.
- `download_url`: a time-limited signed URL to download the exported media file directly,
  along with `download_url_expires_at` indicating when the link expires.

### Republishing

Publishing the same composition a second time automatically reuses the previous share URL,
overwriting its content — so bookmarks and links handed out for the first publish keep working.
Republish matching is keyed on `(project_id, composition_id, media_type)`, so a Video publish
and an Audio publish of the same composition produce two separate share URLs.

### Async Operations

Publish jobs run in the background and return a `job_id`. Monitor progress via the [GET /jobs/{job_id}](#operation/getJob) endpoint,
which returns the `share_url`, `download_url`, and `download_url_expires_at` fields once the job finishes.

### 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).

## Request body

- object — Request to publish a project composition.
  - `project_id` string, uuid, required — The ID of the project to publish.
  - `composition_id` string — Composition to publish. If omitted, the first composition in the project is used. Accepts any of the following formats: - A full composition UUID (e.g. `39677a40-1c43-4c36-8449-46cfbc4de2b5`) - A 5-character short ID from a Descript URL (e.g. `39677`) - A full Descript project URL (e.g. `https://web.descript.com/{project_id}/39677`)
  - `media_type` 'Video' | 'Audio' — Media type of the published output. Defaults to `Video` when omitted. If the target composition has no video content: - omitting `media_type` publishes it as `Audio` (the completed job result reports `media_type: Audio`), - explicitly requesting `Video` is rejected with a 422.
  - `resolution` '480p' | '720p' | '1080p' | '1440p' | '4K' — Resolution for the published output. Only applicable when media_type is Video.
  - `callback_url` string, uri — 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.
  - `access_level` 'public' | 'unlisted' | 'drive' | 'private' — Desired access level for the published share page. If omitted, the drive's configured default is used. Returns 403 if the requested level is not permitted by the drive's publish settings (e.g. requesting `public` when search engine indexing is disabled).

## Response `201`

Publish job created successfully

- object
  - `job_id` string, uuid, required — Unique identifier for the publish job
  - `drive_id` string, uuid, required — Drive ID where the project is located
  - `drive_name` string, nullable — Human-readable name of the connected drive (workspace)
  - `project_id` string, uuid, required — The project ID being published
  - `project_url` string, uri, required — URL to access the project in Descript web app

## Other responses

- `400` — Invalid input: - Malformed request body - Invalid project_id or composition_id format - Invalid media_type or resolution value
- `401` — Unauthorized - missing or invalid authentication token
- `403` — Forbidden: - User doesn't have write access to the project - Project doesn't belong to the token's drive - Requested `access_level` is not permitted by the drive's publish settings
- `404` — Not found: - Composition doesn't exist in the specified project (when `composition_id` is provided)
- `422` — Unprocessable Entity: - `media_type` was explicitly set to `Video` but the target composition has no video content. Retry with `media_type` set to `Audio` (or omit it to publish as audio).
- `429` — Too many requests - rate limit exceeded. Use the `Retry-After` header to determine when to retry.

---

[API](https://skmtc.dev/descriptapi/apis/descript-api.md) · [All operations](https://skmtc.dev/descriptapi/apis/descript-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/descriptapi/descript-api/revisions/04c0005aef70/schema)
