Media Library
Standalone media endpoints for bulk upload, moderation-first workflows, and n:m product linking.
Media items live in a creator's library independently of products. Products reference one or more media rows through the product_media pivot.
List media library
GET /api/media
Returns paginated media owned by the authenticated creator.
Authentication: Required
Query Parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Items per page (default: 20, max: 100) |
status | string | Filter by moderation status: pending, approved, rejected |
folder_id | integer | Filter by content folder |
unlinked | boolean | When true, only media not linked to any product |
Response (200)
{
"success": true,
"errors_message": null,
"data": {
"data": [
{
"id": 101,
"type": "image",
"title": "Beach photo",
"description": null,
"status": "pending",
"preview": "https://...",
"preview_blurred": "https://...",
"source": "https://...",
"folder_id": null,
"folder": null,
"product_ids": [],
"is_linked": false,
"created_at": "2026-06-10T10:00:00+00:00",
"updated_at": "2026-06-10T10:00:00+00:00"
}
],
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}Create media from upload session
POST /api/media
Creates a library media item from a finalized upload session without creating a product.
Authentication: Required
Request Body
{
"upload_session_id": "01knyp9pd50ey9xrpgp1nv0jn0",
"title": "Optional title",
"description": "Optional description",
"folder_id": 12
}Response (201)
Returns a MediaLibraryResource object. Moderation runs on the media row (status: pending until approved).
Bulk upload sessions
POST /api/media/bulk
Starts multiple upload sessions with shared defaults. Use the returned session IDs with the normal upload session flow, then call POST /api/media per file after finalization.
Authentication: Required
Request Body
{
"files": [
{
"file_name": "pic_01.jpg",
"file_size_bytes": 2048000,
"mime_type": "image/jpeg"
},
{
"file_name": "pic_02.jpg",
"file_size_bytes": 1800000,
"mime_type": "image/jpeg"
}
],
"defaults": {
"is_adult_content": true,
"is_downloadable": false,
"is_verif_age": false,
"folder_id": 12
}
}Response (201)
{
"success": true,
"errors_message": null,
"data": [
{ "upload_session_id": "01abc..." },
{ "upload_session_id": "01def..." }
]
}Update media
PATCH /api/media/{media_id}
Edit title, description, or folder assignment on a library item.
Authentication: Required (owner only)
Request Body
{
"title": "Updated title",
"description": "Updated description",
"folder_id": 12
}Delete media
DELETE /api/media/{media_id}
Deletes a library item. Fails with 403 when the media is still linked to one or more products.
Link media to a product
POST /api/products/{product_id}/media
Attach existing library media to a product (n:m).
Request Body
{
"media_ids": [101, 102, 103]
}Unlink media from a product
DELETE /api/products/{product_id}/media/{media_id}
Removes the pivot link only. The media row remains in the library.
Create product from media library
POST /api/products
Accepts media_ids[] instead of uploading a new file:
{
"media_ids": [101, 102, 103],
"price": 1500,
"title": "Summer Bundle",
"is_adult_content": true,
"is_downloadable": false
}The legacy upload_session_id flow on POST /api/products remains supported as a compatibility shim.
Account upload defaults
PATCH /api/user/{user_id}
Store creator-level defaults used to pre-fill bulk uploads and product creation:
{
"upload_defaults": {
"is_adult_content": true,
"is_downloadable": false,
"is_verif_age": false,
"default_price": 500,
"folder_id": 12
}
}default_price is in cents (500 = $5.00). Returned on GET /api/user as upload_defaults.
Moderation
Moderation status is tracked on media rows (veriff_status), not on products. API status values map as:
| API status | Backend states |
|---|---|
pending | Unchecked |
approved | Checked, Manual Approval |
rejected | Manual Removal, AI Removal |
Purchasability still evaluates linked media on each product.