Create upload
Creates the asset and returns the signed URL to upload the file.
First step of an upload. Send the class, the type, and the exact size in bytes. The asset starts as pending_upload.
PUT the file to the url (valid for 15 minutes) with the headers from the response, unchanged. Content-Type and Content-Length are signed: any other value gets a 403 from the storage. Then call complete.
curl -X PUT "$UPLOAD_URL" -H "Content-Type: image/jpeg" -H "Content-Length: 482113" --data-binary @front.jpgWithout storage configured, the answer is 503 STORAGE_UNAVAILABLE.
api_keyAuthorizationBearer <token>API key (mk_...)
sellerId*stringSeller the new resource belongs to.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidIdempotency-Key?stringOptional. A unique value (for example a UUID), 1 to 255 characters, that makes the request safe to retry: repeating it with the same body within 24h returns the original response with Idempotency-Replayed: true instead of running the operation again. Scoped to your account. Reusing it with a different body returns 409.
1 <= length <= 255application/json- body
The file the client is about to upload.
class*stringAccess class of the new asset. Use confidential for documents that must never have a URL.
"confidential""product_media"contentType*stringMedia type of the file. The upload must send it as Content-Type, and the content must match it. application/xml only for confidential.
"image/jpeg""image/png""image/webp""video/mp4""application/pdf""application/xml"sizeBytes*integerExact size of the file, in bytes. The upload must send exactly this many. Ceiling: 10 MiB for images, 100 MiB for MP4, 20 MiB for PDF, 5 MiB for XML.
1 <= value <= 9007199254740991filename?stringFile name used when the asset is downloaded. Without slashes, quotes or control characters.
^[^/\\\p{Cc}"]+$1 <= length <= 255The asset was created pending_upload. PUT the file to url with headers, then complete the upload.
application/json- response
Where and how to send the file. Then call POST /v1/assets/uploads/{uploadId}/complete.
uploadId*stringIdentifier of this upload, for POST /v1/assets/uploads/{uploadId}/complete.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidassetId*stringIdentifier of the asset the upload creates.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidurl*stringSigned URL for one PUT of the file body. Valid until expiresAt.
uriheaders*Headers the PUT must send exactly. They are signed: any other size or type is refused by the storage.
expiresAt*stringWhen the URL stops working (15 minutes). An upload not completed by then ends failed with upload_expired.
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$date-timecurl -X POST "https://example.com/v1/sellers/b6a1c0de-3f0c-4f53-9c6e-2a1d7d3b9e10/assets/uploads" \ -H "Content-Type: application/json" \ -d '{ "class": "product_media", "contentType": "image/jpeg", "sizeBytes": 482113 }'{ "uploadId": "9e2b5f14-6c3d-4e8a-b1f7-0d4c2a6e8b31", "assetId": "4a7f2701-c5f7-477f-9658-5ce6be74ef80", "url": "https://storage.example.com/marketapi-assets/quarantine/9e2b5f14-6c3d-4e8a-b1f7-0d4c2a6e8b31?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900&X-Amz-Signature=5d1b9c", "headers": { "Content-Type": "image/jpeg", "Content-Length": "482113" }, "expiresAt": "2026-10-16T12:15:00.000Z"}