---
title: "Upload collection page media"
method: POST
path: "/api/v2/collections/{slug}/media/{placement}"
tags: ["Collection Endpoints"]
---

# Upload collection page media

`POST /api/v2/collections/{slug}/media/{placement}`

## Request

- Base URL: `https://api.opensea.io`
- URL: `https://api.opensea.io/api/v2/collections/{slug}/media/{placement}`
- Auth: API key in header `x-api-key` and OpenID Connect (`https://auth.opensea.io/.well-known/openid-configuration`, scopes: `write:collections`)
- TypeScript: <https://skmtc.dev/opensea/apis/opensea-api/docs/api/v2/collections/:slug/media/:placement/post.ts> (a function with typed inputs; its response is checked against the schema)

Upload an image or an MP4 video for the collection page: the hero (8:3 on desktop, 16:9 on mobile), about, narrative, content block and team sections. Set the content_type query parameter to the exact MIME type of the file. Video must be video/mp4. Files can be up to 50 MB. This response starts a three-step upload flow. First, request this context from OpenSea. Second, call the returned method at the returned URL. For POST, add every fields entry unchanged as a multipart text field, then add a file part containing the bytes. The file part must be last. Let the HTTP library generate the multipart boundary; do not set the overall multipart Content-Type header yourself. POST storage uploads normally return 204. For PUT, upload the raw bytes, use only headers explicitly required by the endpoint, and expect 200. Treat any 2xx storage response as success. The URL and fields are short-lived sensitive credentials. Do not log, persist, alter, or put them in tickets. Third, after storage succeeds, pass the returned token to the documented OpenSea API endpoint. Do not use the token before the storage upload succeeds. Pass the token in PATCH /api/v2/collections/{slug}/metadata as { image: { token } } for an image or { video: { token } } for a video. The media type must match the upload: a video token sent as image, or the reverse, does not resolve and the metadata update fails with 400 without saving anything. The placement picks where the file is stored, but the token is accepted in any media field of the metadata update. The presigned upload expires about a minute after it is issued.

## Path parameters

- `slug` string, required
- `placement` string, required

## Query parameters

- `content_type` string, required

## Response `200`

Upload context generated successfully

- UploadContext: This response starts a three-step upload flow. First, request this context from OpenSea. Second, call the returned method at the returned URL. For POST, add every fields entry unchanged as a multipart text field, then add a file part containing the bytes. The file part must be last. Let the HTTP library generate the multipart boundary; do not set the overall multipart Content-Type header yourself. POST storage uploads normally return 204. For PUT, upload the raw bytes, use only headers explicitly required by the endpoint, and expect 200. Treat any 2xx storage response as success. The URL and fields are short-lived sensitive credentials. Do not log, persist, alter, or put them in tickets. Third, after storage succeeds, pass the returned token to the documented OpenSea API endpoint. Do not use the token before the storage upload succeeds.
  - `fields` object, required: Short-lived sensitive multipart text fields for POST. Submit every entry unchanged before the file part. Content-Type contains the exact MIME type required by the signed policy. This map is empty for PUT.
  - `method` 'POST' | 'PUT', required: HTTP method to use at url. Current upload contexts use POST.
  - `token` string, required: Reference for the next OpenSea API call. Use it only after storage returns 2xx.
  - `url` string, required: Short-lived storage URL. Use it exactly as returned and treat it as sensitive.

## Other responses

- `400`: For error reasons, review the response data.
- `401`: Invalid or missing API key
- `403`: Wallet token lacks permission for this request
- `404`: Resource not found
- `409`: Conflict
- `500`: Internal server error. Please open a support ticket so OpenSea can investigate.

## Changes

- **2026-11-03** `2c7935d84f90`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/opensea/apis/opensea-api/changes/api/v2/collections/:slug/media/:placement/post.md)

---

[API](https://skmtc.dev/opensea/apis/opensea-api.md) - [All operations](https://skmtc.dev/opensea/apis/opensea-api/llms.txt) - [OpenAPI document](https://skmtc.dev/opensea/apis/opensea-api/revisions/2c7935d84f90?raw)
