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

# Direct file upload

> Upload local files with presigned URLs instead of passing a public URI.

Instead of providing a public URL, you can upload files directly from your local machine using the [import endpoint](/developers/api-reference/import/import-project-media). The flow has three steps: request signed upload URLs, PUT your file bytes, then poll for completion.

## Step 1 — Request upload URLs

Call the import endpoint with `content_type` and `file_size` instead of `url` for each media item you want to upload directly.

**Request**

```bash theme={null}
curl -X POST https://descriptapi.com/v1/jobs/import/project_media \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project_name": "My Upload Project",
    "add_media": {
      "recording.mp4": {
        "content_type": "video/mp4",
        "file_size": 52428800
      }
    },
    "add_compositions": [
      {
        "name": "Main",
        "clips": [
          { "media": "recording.mp4" }
        ]
      }
    ]
  }'
```

The response includes an `upload_urls` object keyed by media reference ID. Each entry contains a signed `upload_url` (valid for 3 hours), plus `asset_id` and `artifact_id` for the created asset.

**Response**

```json theme={null}
{
  "job_id": "project-media-import-a1b2c3d4",
  "drive_id": "c9c5c47e",
  "project_id": "e2f89ce6",
  "project_url": "https://web.descript.com/e2f89ce6",
  "upload_urls": {
    "recording.mp4": {
      "upload_url": "https://storage.googleapis.com/bucket/...",
      "asset_id": "d4e5f6a7-1234-5678-9abc-def012345678",
      "artifact_id": "a1b2c3d4-5678-9abc-def0-123456789abc"
    }
  }
}
```

## Step 2 — Upload the file

PUT the raw file bytes to the signed URL. Use `Content-Type: application/octet-stream`.

```bash theme={null}
curl -X PUT \
  -H "Content-Type: application/octet-stream" \
  --data-binary @recording.mp4 \
  "https://storage.googleapis.com/bucket/..."
```

The import job detects the upload automatically and begins processing.

## Step 3 — Poll for completion

Check the job status the same way as a URL-based import — poll the [job status endpoint](/developers/api-reference/jobs/get-job) with the `job_id`, or provide a `callback_url` in the original request.

```bash theme={null}
curl https://descriptapi.com/v1/jobs/project-media-import-a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

When the job reaches `job_state: "stopped"`, check `result.status` for success or failure.

## Mixing URL imports and direct uploads

You can combine URL-based and direct upload media items in a single request. Items with `url` are fetched server-side; items with `content_type` and `file_size` return signed upload URLs.

```bash theme={null}
curl -X POST https://descriptapi.com/v1/jobs/import/project_media \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project_name": "Mixed Import",
    "add_media": {
      "intro.mp4": {
        "url": "https://example.com/intro.mp4"
      },
      "recording.mp4": {
        "content_type": "video/mp4",
        "file_size": 52428800
      }
    }
  }'
```

The response will include `upload_urls` only for the direct upload items.

## Required fields

| Field          | Type    | Description                                                                       |
| -------------- | ------- | --------------------------------------------------------------------------------- |
| `content_type` | string  | MIME type of the file (e.g., `video/mp4`, `audio/wav`)                            |
| `file_size`    | integer | File size in bytes                                                                |
| `language`     | string  | *(optional)* ISO 639-1 language code for transcription. Auto-detected if omitted. |


## Related topics

- [Call the API directly](/api-and-mcp/other-endpoints.md)
- [Upload a file from your computer](/add-and-manage-media/local.md)
- [Import and upload files into Descript](/getting-started/import-overview.md)
- [Media library: Organize and reuse content across projects](/add-and-manage-media/media-library-overview.md)
- [Exporting Captivate episodes](/export-and-share/captivate.md)
