File Uploads
File uploads in Brandmachine use REST endpoints with multipart/form-data, separate from the GraphQL endpoint. There's a dedicated upload endpoint per resource type (product studio inputs, fashion models, designer resources, patterns, etc.) rather than a single generic upload.
Authentication
All upload endpoints accept the same API token as the GraphQL endpoint:
Authorization: Bearer bm_your_token_here
See Authentication for token generation.
Upload Endpoints
All endpoints accept POST requests with multipart form data. Replace :id placeholders with the relevant UUID.
Product Studio
| Endpoint | Purpose |
|---|---|
POST /api/product-studios/:studioId/inputs/upload | Upload product images to an existing studio |
POST /api/product-studios/zip-upload | Bulk-import via ZIP (see ZIP Upload) |
Campaign / Batch
| Endpoint | Purpose |
|---|---|
POST /api/campaign-images/:campaignImageId/products/upload | Upload product reference images for a campaign image |
POST /api/batches/:batchId/images/upload | Upload batch input images (Shot Planner) |
POST /api/images/upload-edited | Submit an edited version of an existing image |
Fashion Models
| Endpoint | Purpose |
|---|---|
POST /api/fashion-models/upload | Upload a reference image for the casting flow |
POST /api/fashion-models/upload-existing | Direct upload of an existing model (skip casting); requires rights consent |
Designer
| Endpoint | Purpose |
|---|---|
POST /api/designer-instances/resources | Upload an inspiration resource (image/material/color) |
POST /api/designer-revisions/measurement | Trigger measurement extraction from a flat sketch |
Patterns
| Endpoint | Purpose |
|---|---|
POST /api/patterns/upload | Upload a finished pattern image |
POST /api/patterns/references | Upload an inspiration reference for a pattern |
Product Video
| Endpoint | Purpose |
|---|---|
POST /api/product-videos/:videoId/upload | Upload source media for a product video |
Example: Upload a Product Studio Input
cURL
curl -X POST \ https://production.api.brandmachine.shop/api/product-studios/STUDIO_UUID/inputs/upload \ -H "Authorization: Bearer bm_your_token_here" \ -F "file=@/path/to/product.jpg" \ -F "viewType=front"
JavaScript (browser)
async function uploadProductInput(studioId, file, viewType = 'front') {
const formData = new FormData();
formData.append('file', file);
formData.append('viewType', viewType);
const response = await fetch(
`https://production.api.brandmachine.shop/api/product-studios/${studioId}/inputs/upload`,
{
method: 'POST',
headers: {
Authorization: 'Bearer bm_your_token_here',
},
body: formData,
}
);
if (!response.ok) {
throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
}
return response.json();
}
Python
import requests
url = 'https://production.api.brandmachine.shop/api/product-studios/STUDIO_UUID/inputs/upload'
headers = {'Authorization': 'Bearer bm_your_token_here'}
with open('product.jpg', 'rb') as f:
files = {'file': f}
data = {'viewType': 'front'}
response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())
Example: Bulk ZIP Upload
curl -X POST \ https://production.api.brandmachine.shop/api/product-studios/zip-upload \ -H "Authorization: Bearer bm_your_token_here" \ -F "file=@/path/to/import.zip"
The ZIP must follow the ZIP Upload folder structure.
Example: Upload a Designer Inspiration Resource
curl -X POST \ https://production.api.brandmachine.shop/api/designer-instances/resources \ -H "Authorization: Bearer bm_your_token_here" \ -F "designerInstanceId=DESIGN_UUID" \ -F "type=image" \ -F "label=bird chest" \ -F "file=@/path/to/inspiration.jpg"
Valid type values: image, material, color. For material and color, the file is optional; you can include a text-only description field.
Common Form Fields
Field names vary by endpoint, but the common ones are:
| Field | Notes |
|---|---|
file | Binary image content. Required for upload endpoints. |
viewType | Product Studio input view type: front, back, other, cropped. |
label | Human-readable label for designer resources, pattern references. |
type | Designer resource type: image, material, color. |
description | Optional text on designer/pattern resources. |
rightsConsent | Required boolean on /api/fashion-models/upload-existing. |
Refer to introspection or the dashboard for exact field requirements per endpoint.
File Specifications
Supported Image Types
- JPEG (
.jpg,.jpeg) - PNG (
.png) - WebP (
.webp)
Size and Limits
- Single image upload: typically a few MB; larger images are resized server-side.
- ZIP upload: max 20 MB total archive, max 6 images per product. See ZIP Upload for full rules.
- Server-side timeout for uploads is 120 seconds.
Response Format
Successful uploads return JSON describing the created resource. The exact shape depends on the endpoint, but it typically includes an id and any URLs needed downstream:
{
"success": true,
"id": "abc123-...",
"imageKey": "uploads/studio/STUDIO_UUID/abc123.jpg"
}
Errors return a non-2xx status with an error code:
{
"success": false,
"error": {
"code": "INVALID_FILE_TYPE",
"message": "Only JPEG, PNG, and WebP are supported."
}
}
Error Handling
| Code | Description | Solution |
|---|---|---|
FILE_TOO_LARGE | Exceeds the endpoint's size limit | Reduce or split the upload |
INVALID_FILE_TYPE | Unsupported format | Convert to a supported format |
UNAUTHENTICATED | Missing or invalid token | Check the Authorization header |
FORBIDDEN | Token lacks scope | Use a token with the right scope |
INSUFFICIENT_CREDITS | Upload triggers a billable downstream task | Top up via Billing & Credits |
Retry Failed Uploads
async function uploadWithRetry(url, formData, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, {
method: 'POST',
headers: { Authorization: 'Bearer bm_your_token_here' },
body: formData,
});
if (response.ok) return response.json();
if (response.status === 401 || response.status === 403) throw new Error('Auth error');
} catch (error) {
if (attempt === maxRetries) throw error;
await new Promise((r) => setTimeout(r, 1000 * attempt));
}
}
}
Best Practices
- Validate client-side (size, type) to avoid round-trips on bad files.
- Resize large images before uploading. Anything past a couple thousand pixels per side is usually overkill for catalog inputs.
- Use the right endpoint. A campaign reference image goes through the campaign endpoint; a pattern reference goes through the pattern endpoint; mixing them up will return errors.
- Handle webhooks downstream. Many uploads trigger asynchronous AI tasks. Watch your task list via
activeMediaGenerationTasksto know when results are ready.
Need Help?
Contact support@brandmachine.shop for upload-related issues, with the endpoint and any error code from the response.