Assets and media

Complete upload

Checks the uploaded file and makes the asset ready.

POST
/v1/assets/uploads/{uploadId}/complete

Call it after the PUT. The API checks the size and the type from the content (SVG and HTML are refused) and answers the asset as ready, or failed with a failureReason. A failed asset does not recover: create another upload.

It works once per upload:

  • 409 upload_not_received: the file has not reached the storage yet. Upload it and call again.
  • 409 upload_already_completed: this upload was already completed.
  • 409 upload_expired: the 15 minutes passed. Create another upload.

The result is also sent in the asset.ready and asset.failed webhooks.

Authorization

api_key
headerAuthorizationBearer <token>

API key (mk_...)

Path Parameters

uploadId*string

Identifier of the upload, from POST …/assets/uploads.

Match^([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)$
Formatuuid

Header Parameters

Idempotency-Key?string

Optional. 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.

Length1 <= length <= 255

Response Body

The checked asset: ready, or failed with failureReason when the size or the content did not match what was declared (the file was discarded).

application/json
  1. response

A file stored by marketapi: listing media or a confidential document.

id*string

Identifier of the asset.

Match^([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)$
Formatuuid
sellerId*string

Seller that owns the asset.

Match^([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)$
Formatuuid
class*string

Access class. confidential never has a url: read it through GET /v1/assets/{assetId}/content. product_media has a signed url while ready.

Value in"confidential""product_media"
status*string

pending_upload until the upload is completed, processing while it is checked, then ready or failed. New values may be added: do not treat this list as closed.

Value in"pending_upload""processing""ready""failed"
contentType*string

Media type. Declared at the upload and confirmed against the content before ready.

Value in"image/jpeg""image/png""image/webp""video/mp4""application/pdf""application/xml"
sizeBytes*integer

Size of the file, in bytes.

Range1 <= value <= 9007199254740991
sha256*|

SHA-256 of the content, in hex. null until the asset is ready.

Match^[0-9a-f]{64}$
filename*|

File name given at the upload, used in the download. null when none was given.

source*string

How the asset was created: upload by the client, copy of another asset, or brought in by the API (ingestion, marketplace).

Value in"upload""ingestion""copy""marketplace"
failureReason*|

Why the asset is failed: the size or the content did not match what was declared (size_mismatch, content_type_mismatch), the content is not an accepted type (unsupported_content, which includes SVG and HTML), the file is too large (size_exceeded), the upload was never completed (upload_expired) or its check was interrupted (processing_interrupted). null otherwise.

Value in"size_mismatch""size_exceeded""content_type_mismatch""unsupported_content""upload_expired""processing_interrupted"null
url*|

Signed download URL, valid until urlExpiresAt (15 minutes). Only for a ready product_media asset; always null for confidential. Read the asset again for a fresh one.

Formaturi
urlExpiresAt*|

When url stops working. null when there is no url.

Match^(?:(?:\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))$
Formatdate-time
createdAt*string

When the asset was created.

Match^(?:(?:\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))$
Formatdate-time
updatedAt*string

When the asset last changed.

Match^(?:(?:\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))$
Formatdate-time
curl -X POST "https://example.com/v1/assets/uploads/9e2b5f14-6c3d-4e8a-b1f7-0d4c2a6e8b31/complete"
{  "id": "4a7f2701-c5f7-477f-9658-5ce6be74ef80",  "sellerId": "b6a1c0de-3f0c-4f53-9c6e-2a1d7d3b9e10",  "class": "product_media",  "status": "ready",  "contentType": "image/jpeg",  "sizeBytes": 482113,  "sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",  "filename": "front.jpg",  "source": "upload",  "failureReason": null,  "url": "https://storage.example.com/marketapi-assets/assets/4a7f2701-c5f7-477f-9658-5ce6be74ef80?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900&X-Amz-Signature=5d1b9c",  "urlExpiresAt": "2026-10-16T12:15:00.000Z",  "createdAt": "2026-10-16T12:00:00.000Z",  "updatedAt": "2026-10-16T12:00:05.000Z"}