Upload a file
Send an image once and reference it by ID afterwards.
On this page
Uploads are images you have sent to RunDiffusion and can refer back to by ID. Send the bytes once, then use the ID wherever an image is needed instead of resending them.
POST
https://api2.rundiffusion.com/api/v2/uploadsAcceptsOAuth device flowPersonal API Access TokenCompany API Access Token
Request
Headers
AuthorizationstringRequired- Bearer token. This endpoint accepts an OAuth device flow token, a Personal API Access Token, or a Company API Access Token. See Authentication.
Authorization: Bearer eyJhbGciOi… Content-Typestringoptional- multipart/form-data with a boundary. Every HTTP client sets this for you when you hand it a file, so set it yourself only if you are building the body by hand.
Content-Type: multipart/form-data; boundary=…
multipart/form-data with a single file part. There is no JSON body and no
query parameters.
Body (multipart/form-data)
filefileRequired- The image bytes, sent as a multipart file part. Example: -F "file=@portrait.png" with curl, or a Blob appended to FormData in the browser.
curl -X POST https://api2.rundiffusion.com/api/v2/uploads \
-H "Authorization: Bearer $RUNDIFFUSION_TOKEN" \
-F "file=@portrait.png"const form = new FormData();
form.append('file', fileBlob, 'portrait.png');
const upload = await fetch('https://api2.rundiffusion.com/api/v2/uploads', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.RUNDIFFUSION_TOKEN}` },
body: form,
}).then(r => r.json());with open("portrait.png", "rb") as f:
upload = requests.post(
"https://api2.rundiffusion.com/api/v2/uploads",
headers={"Authorization": f"Bearer {os.environ['RUNDIFFUSION_TOKEN']}"},
files={"file": f},
).json()Limits
FormatsJPEG, PNG, WebP, HEIC, HEIF- Anything else is rejected with 415 UNSUPPORTED_MEDIA_TYPE. HEIC and HEIF are converted to JPEG server-side, which changes both the extension and the mime_type you get back.
File size28 MB- Larger files are rejected with 413 UPLOAD_TOO_LARGE.
Dimensions8192 px- Measured on either dimension. Larger images are rejected.
Response
201 Created for a new upload. Re-sending a file the caller has already
uploaded returns 200 OK with the existing record unchanged, so retrying a
request that timed out mid-flight will not create a duplicate.
{
"id": "Yb3kQ9…",
"name": "fa9c1e22-….png",
"mime_type": "image/png",
"size_bytes": 1863245,
"width": 1024,
"height": 1024,
"url": "https://rundiffusion.com/...",
"thumb_url": "https://rundiffusion.com/...",
"created": "2026-07-23T09:31:02Z"
}idstring- The handle for this upload, a 20-character opaque string. This is what you reference later. Example: Yb3kQ9….
namestring | null- The stored filename, generated as {uuid}.{ext}. This is not the filename you sent, so keep your own mapping if the original matters.
mime_typestring | null- MIME type as stored. HEIC and HEIF uploads report image/jpeg here, because they were converted.
size_bytesinteger | null- Size of the stored file in bytes.
widthinteger | null- Pixel width of the stored image.
heightinteger | null- Pixel height of the stored image.
urlstring | null- Signed download URL, valid for roughly seven days. Treat it as opaque and re-list to refresh it rather than storing it.
thumb_urlstring | null- Signed URL to a 512x512 WebP thumbnail, same seven-day expiry. Falls back to the same value as url until the thumbnail has been generated.
createdstring (ISO 8601)- When it was created, in UTC.
Errors
400INVALID_REQUEST- No file part, an empty file, or a malformed multipart body.
401UNAUTHENTICATED- Missing, malformed, or expired token.
413UPLOAD_TOO_LARGE- The file exceeds 28 MB. details carries the size you sent and the max, so you can report both.
415UNSUPPORTED_MEDIA_TYPE- The declared type is not one of the allowed formats. details.allowed lists them.
429RATE_LIMITED- Too many requests. Uploads are capped hourly rather than per minute. See Rate limits.
502UPSTREAM_UNAVAILABLE- Storage was unreachable. Safe to retry.
See Errors for the full envelope and the code list.
Referencing an upload
The id from this response is the handle. Keep it alongside your own record of
the image, since the stored name will not match the filename you sent.
