Files
All endpoints require a valid API key in the Authorization header.
File delivery uses a two-step upload process: request a presigned upload URL, upload the file directly to S3, then confirm the upload.
Upload flow
- Call Generate upload URL to get a presigned S3 URL
PUTthe file to the presigned URL- Call Confirm upload to finalize
Generate upload URL
POST /v1/files/upload-urlScope: files:write
Request body
{ "file_name": "course-module-1.pdf", "file_size": 5242880, "mime_type": "application/pdf", "product_id": "prod_xyz"}| Field | Required | Description |
|---|---|---|
file_name | Yes | File name (max 255 chars, no path traversal characters) |
file_size | Yes | File size in bytes |
mime_type | Yes | MIME type (must be in the allowed list below) |
product_id | No | Associate with a product |
Response
201 Created
{ "data": { "upload_url": "https://s3.amazonaws.com/...", "file_id": "file_001", "file": { "id": "file_001", "file_name": "course-module-1.pdf", "file_size": 5242880, "mime_type": "application/pdf", "upload_status": "PENDING", "created_at": "2026-03-01T12:00:00.000Z" } }, "meta": { "request_id": "req_abc123", "timestamp": "2026-03-01T12:00:00.000Z" }}The presigned URL expires after 1 hour. Upload the file with a PUT request:
curl -X PUT -T course-module-1.pdf \ -H "Content-Type: application/pdf" \ "https://s3.amazonaws.com/..."Allowed MIME types
| Category | Types |
|---|---|
| Documents | application/pdf, text/plain, text/csv |
| Archives | application/zip, application/x-zip-compressed, application/epub+zip |
| Office | .docx, .xlsx, .pptx (OpenXML formats) |
| Images | image/jpeg, image/png, image/gif, image/webp, image/svg+xml |
| Audio | audio/mpeg, audio/wav, audio/ogg, audio/flac, audio/aac |
| Video | video/mp4, video/webm, video/quicktime |
| Fonts | font/ttf, font/otf, font/woff, font/woff2 |
Errors
| Code | Status | Description |
|---|---|---|
MISSING_REQUIRED_FIELD | 400 | Missing or invalid required field |
FILE_TOO_LARGE | 400 | Exceeds plan’s max file size |
STORAGE_LIMIT_REACHED | 402 | Merchant storage quota exceeded |
Confirm upload
POST /v1/files/{file_id}/confirmScope: files:write
Confirms the file was uploaded to S3 successfully. Validates the file exists and its size is within tolerance (10% of declared size).
Response
{ "data": { "id": "file_001", "file_name": "course-module-1.pdf", "file_size": 5242880, "mime_type": "application/pdf", "upload_status": "CONFIRMED", "download_count": 0, "product_id": "prod_xyz", "created_at": "2026-03-01T12:00:00.000Z", "updated_at": "2026-03-01T12:00:05.000Z" }, "meta": { "request_id": "req_abc123", "timestamp": "2026-03-01T12:00:05.000Z" }}Publishes a file.uploaded webhook event.
Errors
| Code | Status | Description |
|---|---|---|
FILE_NOT_FOUND | 404 | File doesn’t exist |
UPLOAD_NOT_CONFIRMED | 409 | File not in PENDING status or not found in S3 |
Download file
GET /v1/files/{file_id}/download?entitlement_id={ent_id}&customer_id={cust_id}Scope: files:read
Generates a signed CloudFront download URL (60-second TTL).
Query parameters
| Parameter | Required | Description |
|---|---|---|
entitlement_id | Yes | Entitlement granting access |
customer_id | Yes | Customer requesting the download |
Validation
The endpoint validates:
- The entitlement exists and belongs to the customer
- The entitlement status is
ACTIVE - The file belongs to the entitled product
- The file upload status is
CONFIRMED - Bandwidth limits are not exceeded
Response
{ "data": { "download_url": "https://cdn.simplersuite.co/download/...", "download": { "id": "dl_abc123", "file_id": "file_001", "entitlement_id": "ent_abc123", "downloaded_at": "2026-03-01T12:05:00.000Z" } }, "meta": { "request_id": "req_abc123", "timestamp": "2026-03-01T12:05:00.000Z" }}Each download:
- Creates a download record
- Increments the file’s download count
- Tracks bandwidth usage against the merchant’s plan
- Publishes a
download.completedwebhook event
Errors
| Code | Status | Description |
|---|---|---|
MISSING_REQUIRED_FIELD | 400 | Missing required query parameters |
NOT_FOUND | 404 | File or entitlement not found |
UPLOAD_NOT_CONFIRMED | 400 | File not ready for download |
BANDWIDTH_LIMIT_REACHED | 402 | Bandwidth quota exceeded |
Plan limits
| Plan | Max file size | Storage | Included bandwidth |
|---|---|---|---|
| Free | 50 MB | 100 MB | 1 GB (hard cap) |
| Growth | 200 MB | 1 GB | 10 GB |
| Pro | 1 GB | 10 GB | 100 GB |
| Enterprise | 5 GB | 100 GB | 1 TB |
Paid plans support bandwidth overage billing. The Free plan enforces a hard cap.