---
title: "Request a direct-to-S3 upload URL"
method: POST
path: "/api/assets/upload/create-url"
tags: ["Media"]
---

# Request a direct-to-S3 upload URL

`POST /api/assets/upload/create-url`

## Request

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

Step 1 of a 3-step direct upload (create-url -> PUT -> complete). Returns a
pre-signed S3 PUT URL and an uploadId. Validates the type + declared size
and pre-charges your storage quota (refunded if you never complete or the
real file is smaller). Then PUT the bytes to uploadUrl with a matching
Content-Type header, and call complete.

## Request body

- object
  - `filename` string, required
  - `contentType` 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif' | 'video/mp4' | 'video/webm', required
  - `sizeBytes` integer, required: Declared byte size (<= 50MB and within remaining quota).

## Response `201`

Upload URL issued

- object
  - `success` boolean
  - `data` object
    - `uploadId` string
    - `uploadUrl` string: Pre-signed S3 PUT URL.
    - `key` string
    - `expiresInSeconds` integer

## Other responses

- `400`: No current team selected, unsupported contentType, or invalid sizeBytes
- `401`: Missing or invalid API key
- `402`: Storage limit reached or file exceeds remaining storage
- `413`: Declared size exceeds the 50MB per-upload cap

---

[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)
