API documentation
Base URL: https://cdn.saurus.qzz.io. Every API response is JSON. Uploads need no key. Responses use the same envelope everywhere.
Upload
| Method and path | Description |
|---|---|
POST /api/upload | Upload with mode=permanent|temp (default permanent). |
POST /api/upload/permanent | Always permanent. |
POST /api/upload/temp | Always temporary. Optional expires in seconds (60 to 2592000; default is the server's TEMP_EXPIRATION). |
Send multipart/form-data with one to three file fields. Content-Length is required. Success returns 201 for a new file and 200 when identical content already exists (duplicate: true).
{
"success": true,
"data": {
"id": "aB91",
"url": "https://cdn.saurus.qzz.io/image/aB91.png",
"type": "image",
"name": "photo.png",
"mime": "image/png",
"size": 48213,
"sha256": "9f86d0…",
"permanent": false,
"createdAt": "2026-10-06T10:00:00.000Z",
"expiresAt": "2026-10-07T10:00:00.000Z",
"duplicate": false,
"deleteToken": "c1f0…"
}
}
With several files the response is {"success":true,"data":{"files":[…]}} and each entry has its own success. deleteToken is returned only for newly stored files. Keep it if you want to delete the file later.
Look up and delete
| Method and path | Description |
|---|---|
GET /api/file/:id | File metadata. The id may include the extension. |
GET /api/file/:type/:filename | The file itself, same as the public URL. type is image, video, audio or file. |
DELETE /api/file/:id | Delete. Send X-Delete-Token from the upload response, or an admin Authorization: Bearer header. |
Serving and streaming
Files live at /image/<id>.<ext>, /video/…, /audio/… and /file/…. Images, video, audio and PDFs render inline. Archives download. HTML, PHP, JS and other code files are always delivered as text/plain with nosniff and a sandbox policy, so nothing uploaded can run on this origin. Add ?download=1 to force a download.
All files support Range: bytes=start-end and answer with 206 Partial Content, Content-Range and Accept-Ranges: bytes, so video seeks without downloading the whole file. Permanent files are cached for a year; temporary files are cached no longer than they have left, and expired files return 410.
Health and status
GET /api/health returns {"success":true,"data":{"status":"ok"}}. GET /api/status returns size limits and the current rate limit.
Examples
cURL
curl -F "file=@photo.png" https://cdn.saurus.qzz.io/api/upload/permanent curl -F "file=@build.zip" -F "expires=3600" https://cdn.saurus.qzz.io/api/upload/temp curl -X DELETE -H "X-Delete-Token: $TOKEN" https://cdn.saurus.qzz.io/api/file/aB91 curl -H "Range: bytes=0-1023" -o part.bin https://cdn.saurus.qzz.io/video/dHay.mp4
JavaScript (fetch)
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('mode', 'temp');
form.append('expires', '86400');
const res = await fetch('https://cdn.saurus.qzz.io/api/upload', { method: 'POST', body: form });
const json = await res.json();
if (!json.success) throw new Error(json.error.code + ': ' + json.error.message);
console.log(json.data.url);
Python
import requests
with open("photo.png", "rb") as f:
r = requests.post(
"https://cdn.saurus.qzz.io/api/upload/permanent",
files={"file": ("photo.png", f)},
timeout=60,
)
body = r.json()
if r.status_code == 429:
print("retry after", r.headers.get("Retry-After"))
elif body["success"]:
print(body["data"]["url"])
else:
print(body["error"])
Errors
Failures use this shape with a matching HTTP status:
{ "success": false, "error": { "code": "RATE_LIMITED", "message": "Too many requests" } }
| Code | Status | Meaning |
|---|---|---|
| RATE_LIMITED | 429 | Slow down; see the Retry-After header (seconds). |
| FILE_TOO_LARGE | 413 | Over the size limit. |
| INVALID_EXTENSION | 400 | Missing or malformed file extension. |
| INVALID_FILE_CONTENT | 415 | Content does not match the extension (for example a .png that is not a PNG). |
| UNSUPPORTED_MEDIA_TYPE | 415 | Request was not multipart/form-data. |
| NO_FILE, EMPTY_FILE, MALFORMED_REQUEST | 400 | Missing, empty or unreadable upload. |
| NOT_FOUND | 404 | No such file. |
| EXPIRED | 410 | Temporary file has expired. |
| UNAUTHORIZED | 401 | Wrong delete token or admin secret. |
| STORAGE_ERROR, STORAGE_BUSY | 502, 503 | Storage backend problem. Retry later. |
Limits
Default: 25 MB per file, 10 image or video uploads per 20 seconds per IP (other file types get three times that), up to 3 files per request. Temporary files last between 1 minute and 30 days. Identical content is stored once and the existing URL is returned. Do not upload anything you are not allowed to share.