Get Part URLs
POST /api/videos/uploads/{uploadSessionId}/files/{uploadId}/part-urls
Fetch presigned upload URLs for one file within a direct upload group.
Allowed API Key Roles
Route Parameters
uploadSessionId: string UUID for the upload groupuploadId: string UUID for the file within that group
Request Body
partNumbers: array of positive integers, optionalstartPartNumber: positive integer, optionalcount: positive integer up to10000, optional
For multipart uploads, use one of these two styles:
- A specific list of parts with
partNumbers - A range starting at
startPartNumberforcountparts
For most files, start at 1 and request the total number of parts.
For very large files, you can request smaller batches to improve response times by signing fewer part URLs at once.
Use partNumbers when you need a small set of specific parts, such as retries after a failed upload.
Behavior Notes
- Single-part uploads return one presigned URL.
- Multipart uploads return one presigned URL for each requested part.
- The same file may be queried multiple times until it expires, is completed, or is canceled.
Response Shape
uploadId: stringfileRole: stringfileName: stringtotalBytes: numberpartSizeBytes: numbertotalParts: numberuploadStrategy:"single_put" | "multipart"status: stringparts: array
Each parts[] item includes:
partNumber: numbersizeBytes: numberbyteStart: numberbyteEnd: numberurl: stringexpiresAt: string
Uploading to the Presigned URL
Once you receive a presigned URL, upload directly to that URL with an HTTP PUT request.
- Do not send your SpatialGen API key to the presigned URL.
- Send the file bytes directly in the request body.
- For multipart uploads, each URL is for one specific part number.
Single-Part Uploads
For single_put, send the full file to the returned url.
const response = await fetch(part.url, { method: 'PUT', headers: { 'Content-Type': file.type || 'application/octet-stream', }, body: file,})Multipart Uploads
For multipart, slice the file using byteStart and byteEnd, then PUT that slice to the matching url.
const chunk = file.slice(part.byteStart, part.byteEnd + 1)
const response = await fetch(part.url, { method: 'PUT', body: chunk,})
const etag = response.headers.get('ETag')Save the ETag for each uploaded part. You will send those partNumber and etag values to the complete endpoint when you finalize the file upload.
Example Request
fetch('https://spatialgen.com/api/videos/uploads/5ea97a59-95e0-4c8b-a634-b0fa9976f6ff/files/402f0bda-a0fa-4551-ae28-7300ab6678dd/part-urls', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-SPATIALGEN-APPKEY': apiKey, }, body: JSON.stringify({ startPartNumber: 1, count: 13, }),})Example Response
{ "uploadId": "402f0bda-a0fa-4551-ae28-7300ab6678dd", "fileRole": "video_left", "fileName": "left-eye.mov", "totalBytes": 1287340032, "partSizeBytes": 104857600, "totalParts": 13, "uploadStrategy": "multipart", "status": "uploading", "parts": [ { "partNumber": 1, "sizeBytes": 104857600, "byteStart": 0, "byteEnd": 104857599, "url": "https://s3.us-west-004.spatialgen.com/sg-library/42/direct-uploads/5ea97a59-95e0-4c8b-a634-b0fa9976f6ff/402f0bda-a0fa-4551-ae28-7300ab6678dd/Ab3dEfGhJkLmNoPqRsTuV.mov?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...", "expiresAt": "2026-05-06T18:42:11.000Z" } ]}