---
title: "Complete a direct-to-S3 upload"
method: POST
path: "/api/assets/upload/complete"
tags: ["Media"]
---

# Complete a direct-to-S3 upload

`POST /api/assets/upload/complete`

## Request

- Base URL: `https://api-app.postnext.io`
- URL: `https://api-app.postnext.io/api/assets/upload/complete`
- Auth: API key in header `x-api-key`

Step 3 of the direct upload. Verifies the uploaded object, reconciles the
storage charge to the real size, moves it to a permanent location, and
creates the asset. Returns the asset (reference its id in a post).

## Request body

- object
  - `uploadId` string, required

## Response `201`

Asset created

- object
  - `success` boolean
  - `data` Asset
    - `_id` string
    - `teamId` string
    - `userId` string
    - `folderId` string, nullable
    - `name` string: Stored (S3) filename.
    - `originalName` string
    - `type` string: MIME type (stored under `type`, not `mimeType`).
    - `url` string, uri
    - `size` integer: Bytes.
    - `width` integer
    - `height` integer
    - `displayName` string
    - `source` 'user_upload' | 'unsplash' | 'pixabay' | 'pexels' | 'brand_scraper' | 'ai_generated' | 'other'
    - `createdAt` string, date-time
    - `updatedAt` string, date-time

## Other responses

- `400`: uploadId is required
- `401`: Missing or invalid API key
- `404`: Session not found/expired, or no uploaded object
- `413`: Uploaded object is larger than the declared sizeBytes; re-issue create-url with the correct size
- `415`: Uploaded bytes do not match the declared type

---

[API](https://skmtc.dev/postnext/apis/postnext-public-api.md) · [All operations](https://skmtc.dev/postnext/apis/postnext-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/postnext/apis/postnext-public-api/revisions/c0bf3aa03271?raw)
