---
title: "Confirm upload completion"
method: POST
path: "/v2/media/{media_id}/upload/complete"
tags: ["v2 - Media"]
---

# Confirm upload completion

`POST /v2/media/{media_id}/upload/complete`

## Request

- Base URL: `https://api.jubjubapp.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.jubjubapp.com/v2/media/{media_id}/upload/complete`
- Auth: HTTP bearer

Call this after successfully uploading the file to GCS.

    This will:
    1. Validate the Media exists and is in 'uploading' status
    2. Make the file publicly accessible
    3. Extract video metadata (width, height, fps, codec, etc.) for Smart Tags
    4. Update Media status to 'ready'
    5. Return the complete Media with public URL and video_metadata

## Path parameters

- `media_id` string, required

## Headers

- `Authorization` string
- `X-JubJub-Service-Key` string
- `X-JubJub-Agent-Key` string
- `X-JubJub-Platform-Key` string
- `Origin` string
- `Referer` string
- `X-JubJub-Trial-Token` string

## Request body

- MediaUploadCompleteDTO: Request to confirm upload completion. The frontend sends this after successfully uploading the file to GCS.
  - `size_bytes` integer, required: Final file size in bytes (frontend knows this after upload).

## Response `200`

Successful Response

- MediaResponseDTO: Full media response. Returned after upload completion or when fetching media details.
  - `media_id` string, required
  - `workspace_id` string, required
  - `type` string, required: Media type: video, image, subtitle or document (a PDF)
  - `filename` string, required
  - `content_type` string, required
  - `size_bytes` integer, required
  - `duration_seconds` number, nullable: Duration in seconds (for videos)
  - `status` string, required: Processing status: uploading, processing, ready, failed, unreadable. `unreadable` is terminal: the bytes are not a usable file of their type, the stored object has been deleted, and re-uploading the same file will not help.
  - `status_reason` string, nullable: Why, in plain words, when the status needs explaining. Set with `unreadable`; null otherwise. Safe to show to the person.
  - `url` string, nullable: Signed URL of the file, valid for 120 minutes (when status is 'ready'). A document's URL opens inline as application/pdf. An image's URL is the original only for its uploader; everyone else gets a copy with EXIF (GPS included) removed, and null when that copy could not be made.
  - `video_metadata` MediaVideoMetadataDTO: Video-specific metadata for Smart Tags and Smart Rename.
    - `width` integer, nullable: Video width in pixels
    - `height` integer, nullable: Video height in pixels
    - `fps` number, nullable: Frames per second
    - `codec` string, nullable: Video codec (h264, h265, etc)
    - `bitrate_kbps` integer, nullable: Bitrate in kbps
    - `aspect_ratio` string, nullable: Aspect ratio like '16:9', '9:16', '1:1'
    - `resolution` string, nullable: Resolution label like '1080p', '4K', '720p'
    - `orientation` string, nullable: Orientation: 'horizontal', 'vertical', or 'square'
    - `duration_category` string, nullable: Duration category: 'short', 'reel', 'medium', 'long'
  - `image_metadata` MediaImageMetadataDTO: Image-specific metadata, from the Pillow probe at upload completion.
    - `width` integer, nullable: Image width in pixels
    - `height` integer, nullable: Image height in pixels
    - `aspect_ratio` string, nullable: Aspect ratio like '1:1', '4:5', '1.91:1', '16:9'
    - `orientation` string, nullable: Orientation: 'horizontal', 'vertical', or 'square'
    - `format` string, nullable: Stored format as a mime type: image/jpeg, image/png, image/webp, image/gif
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/jubjubapp/apis/jubjub-api.md) - [All operations](https://skmtc.dev/jubjubapp/apis/jubjub-api/llms.txt) - [OpenAPI document](https://skmtc.dev/jubjubapp/apis/jubjub-api/revisions/353157b296f2?raw)
