Storage
Per-project S3-compatible object storage. Use presigned URLs for upload and download — no SDK required, works from any HTTP client.
Upload a file
# Step 1 — ask Mosaic for a presigned upload URL curl -X POST $API/{slug}/storage/upload \ -H "X-API-Key: $KEY" -H "Content-Type: application/json" \ -d '{ "filename": "photos/cat.jpg", "content_type": "image/jpeg", "expires": 3600 }' # Response: { "upload_url": "https://s3.mosaic.site/...", "method": "PUT", ... } # Step 2 — PUT the raw bytes to that URL curl -X PUT -H "Content-Type: image/jpeg" \ --data-binary @cat.jpg "$UPLOAD_URL"
Why two stepsBrowser clients can upload large files directly to S3 without proxying through your server. The presigned URL embeds the auth — no key ever leaves the backend.
Download a file
# Get a short-lived download URL curl $API/{slug}/storage/download/photos/cat.jpg -H "X-API-Key: $KEY"
List + delete
# List (optional prefix filter) curl "$API/{slug}/storage/files?prefix=photos/" -H "X-API-Key: $KEY" # Delete curl -X DELETE "$API/{slug}/storage/files/photos/cat.jpg" -H "X-API-Key: $KEY"
Best practices
- Organize with prefixes —
uploads/,avatars/,documents/ - Set accurate
content_typeso browsers render inline correctly - Store the path in your database, not the presigned URL — URLs expire
- Containers are ephemeral — never write user uploads to local disk
Endpoints
| Endpoint | Method | Description |
|---|---|---|
| /{slug}/storage/files | GET | List files (optional ?prefix=) |
| /{slug}/storage/upload | POST | Get presigned upload URL |
| /{slug}/storage/download/{path} | GET | Get presigned download URL |
| /{slug}/storage/files/{path} | DELETE | Delete file |