Upload Storefront Media
Host a file for a storefront (Creator page) and return a URL. The saved draft
is not changed — PATCH the returned file_url into
header,
settings, or a
widget.
The path is nested under the storefront UUID. A missing storefront is 404
before the file is hosted.
The body is multipart/form-data, not JSON. Use curl -F (or equivalent)
and do not send Content-Type: application/json — the client must set the
multipart boundary.
Skip this endpoint when the URL is already a public http:// or https://
link. Storefront PATCHes store that URL as given; they do not fetch and
rehost it the way product image_url
does.
type=image is a photo or a video. Raster stills come back with a .webp
file_url — use the returned value, not the original extension. Video bytes
return type=video; PATCH that file_url into header.photo.video_src_url (or a
widget video_src_url), not src_url.
type=file returns a private locator for config.file, not a public
download. PATCH config.file = { name, url, external: false }. Do not GET
url. There is no download_url (unlike
product files).
There is no preview_url.
This endpoint also allows 60 uploads per 60 seconds per store, in addition to the API-wide 100 requests per 60 seconds. The 60-upload budget is shared with Upload Product Media and completing an upload. See Rate limiting.
Request
POST /storefronts/{id}/media
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Storefront UUID |
Request Body
multipart/form-data. file and type are required; there is no default
for type. Size is limited by the store's upload limit (default 100 MB).
| Parameter | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file to host. |
type | string | Yes | image or file. image hosts a photo or video. file hosts a private locator for config.file. |
Example Requests
Host a PNG as type=image. Raster stills come back .webp; the response
file_url ends in .webp even when name keeps the original filename:
curl -X POST "https://cart.easy.tools/api/v1/storefronts/b10f5980-d653-4494-ad1c-6a9d68c96d19/media" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "type=image" \
-F "file=@storefront-upload.png"
Host a PDF as type=file:
curl -X POST "https://cart.easy.tools/api/v1/storefronts/b10f5980-d653-4494-ad1c-6a9d68c96d19/media" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "type=file" \
-F "file=@storefront-upload.pdf"
Response
Success Response (201)
Returns the hosted file. name is the original filename. type is detected
from the file contents (image, video, or file) and can differ from the
request type.
PNG uploaded with type=image:
{
"name": "storefront-upload.png",
"file_url": "https://cdn.example.com/storefront-media/4yTMGS7pzSNHGW68Q97zpBNR0z0cVHJg.webp",
"type": "image"
}
PDF uploaded with type=file:
{
"name": "storefront-upload.pdf",
"file_url": "https://cdn.example.com/storefront-files/ZwK3vCSQZDImaBsXu1qdXQ5c61Nc6A4o.pdf",
"type": "file"
}
Response Fields
See Media Upload Object.
Error Responses
Bad Request (400)
Returned when {id} is not a UUID.
{
"message": "Invalid storefront ID"
}
Not Found Error (404)
Returned when the UUID does not exist, belongs to another store, or points at a deleted storefront. The storefront is checked before the file is hosted.
{
"message": "Storefront not found"
}
Validation Error (422 Unprocessable Entity)
Returned when file or type is missing, type is not image or file,
the file is over the store's upload limit, the file is HEIC/HEIF or AVIF, or
type=image is used with bytes that are not an image or a video.
{
"message": "HEIC/HEIF is not supported. Please convert to JPG or PNG before uploading.",
"errors": {
"file": [
"HEIC/HEIF is not supported. Please convert to JPG or PNG before uploading."
]
}
}
Unauthorized (401)
{
"message": "Unauthenticated."
}
Forbidden (403)
Returned when your API key has not been granted access to the requested store.
{
"message": "You do not have API access to the requested store."
}
Too Many Requests (429)
Returned when you exceed the API-wide rate limit or the shared 60 uploads
per 60 seconds. The Retry-After response header gives the
number of seconds to wait.
{
"message": "Too many requests. Please retry after 60 seconds."
}