---
title: "Create a presigned direct-to-S3 upload slot."
method: POST
path: "/media/uploads"
tags: ["Media"]
---

# Create a presigned direct-to-S3 upload slot.

`POST /media/uploads`

Returns a short-lived presigned S3 `PUT` URL so a client can upload large binary
artifacts (e.g. Revel Digital `.webapp` zip bundles) DIRECTLY to storage without the
bytes streaming through the API. After uploading, call
`POST /media/uploads/{id}/finalize` to ingest the object into the media library.
            
The account is always derived from the authenticated key/token — never from the body.
The presigned URL is scoped to a single object key under the account's namespace, so it
can never overwrite another account's objects.
            
Three-step flow:
```
# 1) Request a slot
curl -X POST "https://api.reveldigital.com/api/media/uploads" \
     -H "X-Reveldigital-Apikey: <API_KEY>" \
     -H "Content-Type: application/json" \
     -d '{ "name": "myapp.webapp", "group_id": "<GROUP_ID>", "tags": ["env=Production"], "content_type": "application/zip" }'
            
# 2) Upload the bytes straight to S3 (Content-Type MUST match the returned header)
curl -T myapp.webapp -H "Content-Type: application/zip" "<upload_url>"
            
# 3) Finalize / ingest
curl -X POST "https://api.reveldigital.com/api/media/uploads/<id>/finalize" \
     -H "X-Reveldigital-Apikey: <API_KEY>"
```
            
All media types supported by the multipart upload work here too (images, audio, video,
presentations, PDF, and `.webapp` bundles): finalize downloads the staged object to
the server and runs the SAME ingestion pipeline, so video is transcoded just as it is for
a multipart upload.

## Request body

- MediaUploadRequest — Request body for creating a direct-to-S3 upload slot via `POST /media/uploads`.
  - `name` string, nullable — The file name of the asset to upload, including extension (e.g. `myapp.webapp`). The extension determines the resulting media type, so preserve `.webapp` for webapp bundles.
  - `group_id` string, nullable — Optional media group id the finalized media will be placed in. When omitted the account's root media group is used.
  - `tags` string[], nullable — Optional tags applied to the finalized media (stored newline-delimited on the media record).
  - `content_type` string, nullable — Optional content type the client will send on the S3 PUT. Defaults to `application/zip` for `.webapp` bundles, otherwise the type inferred from the file extension. The value is pinned into the presigned signature and the client MUST send the same header.
  - `advertiser_id` string, nullable — Optional advertiser/user id the finalized media is attributed to.
  - `is_shared` boolean, nullable — Optional flag marking the finalized media as shared with other accounts.
  - `size` integer, nullable — Optional declared object size in bytes. When supplied it is validated against the configured maximum up front; the real size is always re-validated at finalize.

## Response `201`

Returns the created upload slot

- MediaUploadResponse — Response returned from `POST /media/uploads` describing the presigned S3 PUT slot.
  - `id` string, nullable — The opaque upload slot id. Use it to finalize (`POST /media/uploads/{id}/finalize`) or to query status (`GET /media/uploads/{id}`).
  - `upload_url` string, nullable — The presigned S3 URL the client uploads the raw bytes to.
  - `method` string, nullable — The HTTP method to use against RevelDigital.Core.PublicApi.Models.MediaUploadResponse.UploadUrl. Always `PUT`.
  - `headers` object, nullable — The exact headers the client MUST send on the upload request (at minimum `Content-Type`).
  - `key` string, nullable — The S3 object key the bytes are written to. Scoped to the authenticated account.
  - `expires_at` string, date-time — The UTC time the presigned URL expires (ISO-8601).

## Other responses

- `400` — If the request is invalid (bad name, file type, group, or size)

---

[API](https://skmtc.net/reveldigital/apis/revel-digital-rest-api.md) · [All operations](https://skmtc.net/reveldigital/apis/revel-digital-rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/reveldigital/revel-digital-rest-api/revisions/f23a94aea621/schema)
