Upload a product image
Uploads one image file and adds it to a product in the slot given by rank. Send the request as multipart/form-data. The image is stored and resized on upload, which takes a few seconds; the response's url is immediately downloadable.
A product has 4 image slots, rank 0 to 3, and the image with the lowest rank is the product's primary image. Read the product with GET /public/v1/products/{id} to find a free slot (a product with no images has all four free). Uploading into a taken slot is rejected with a 400, so it is safe to retry an upload that timed out: if the first attempt landed, the retry fails instead of adding a duplicate. A product that already has 4 images takes no more until one is deleted with DELETE /public/v1/product-images/{id}.
The file must be a JPEG, PNG or GIF of at most 10 MB; the type is read from the file's contents, not its name. Convert WebP or HEIC images first.
The upload updates the product's updated_datetime and sends a product update webhook. It does not touch inventory or push anything to Metrc or BioTrack.
Required permission: products_permissions_edit (plus access to the product under team restrictions).
BearerAuthorizationBearer <token>API token generated in Distru (Settings → Distru API). Send it on every request as Authorization: Bearer YOUR_API_TOKEN.
multipart/form-data- body
file*unknownThe image file: a JPEG, PNG or GIF of at most 10 MB. Required and must be non-empty.
product_id*stringID of the product to add the image to. An ID that doesn't exist for your company returns 404.
rank*integerThe image's slot, 0 to 3; 0 is the primary image. Must be free on the product.
Image uploaded
*/*- response
A single product image wrapped in a data envelope
data?An image as shown in Distru
curl -X POST 'https://app.distru.com/public/v1/product-images' \ -F 'file=null' \ -F 'product_id=550e8400-e29b-41d4-a716-446655440000' \ -F 'rank=0'{ "data": { "id": "00000000-0000-0000-0000-000000000008", "name": "data.png", "rank": 1, "url": "https://example.com/your-file" }}