Text promotions skip this step entirely. If your content is plain text or HTML, provide it inline via the
content field when creating a promotion.Content-Range headers.
Initiate the upload
Request:Response:
uploadUrlis the relative path for chunk uploads.maxChunkSizeis the maximum bytes per chunk (default 50 MB). The final chunk may be smaller.
Upload the file in chunks
Send the file bytes as one or more PUT requests with a Response (200 OK):Multiple chunks (large file):Content-Range format:
Content-Range header.Single chunk (file smaller than maxChunkSize):bytes <start>-<end>/<total> where start and end are zero-based inclusive byte offsets and total is the full file size.- Multiple files can be uploaded in parallel. Hold onto all
uploadIdvalues, as you’ll reference them when creating the promotion. - If a chunk fails due to a network error, check the upload status to see how many bytes were received, then resume from that offset.
- Uploading to an already-completed upload returns 409 Conflict.
Code Example (TypeScript)
Below is a self-contained TypeScript example that demonstrates the full upload flow, including chunked uploads for large files. Run withnpx tsx upload.ts <file-path> [content-type].
Common Error Scenarios
| Scenario | HTTP Status | Error Code | What to do |
|---|---|---|---|
| File too large for its format | 413 | PAYLOAD_TOO_LARGE | Check file size limits in Supported File Formats |
Missing Content-Range header | 400 | VALIDATION_ERROR | Add Content-Range: bytes <start>-<end>/<total> |
| Chunk body size does not match range span | 400 | VALIDATION_ERROR | Ensure byte length of body equals end - start + 1 |
Content-Range total does not match declared fileSize | 400 | VALIDATION_ERROR | Use the same total in every chunk as the fileSize from initiation |
| Upload already completed | 409 | INVALID_REQUEST | The file is already uploaded; proceed to create the promotion |
| Upload not found | 404 | NOT_FOUND | The upload ID is invalid or the session expired; initiate a new upload |
| Network failure mid-upload | N/A | N/A | GET the upload status to check bytesReceived, then resume from that offset |