API Documentation
CloudStorage provides a fully S3-compatible API. Use your existing tools, SDKs, and workflows with a single endpoint change.
Quickstart
Get up and running in under two minutes.
Create an account
Sign up at cloudstorage.io/signup. You will receive your first S3 access key and a default bucket automatically.
Configure your client
Point any S3-compatible client at our endpoint.
aws configure
# Access Key ID: your-access-key
# Secret Access Key: your-secret-key
# Region: eu-central-1
# Set the endpoint for all commands
export AWS_ENDPOINT_URL=https://s3.cloudstorage.ioUpload your first file
Use any S3 operation you already know.
aws s3 --endpoint-url https://s3.cloudstorage.io \
cp ./my-file.txt s3://my-bucket/my-file.txtEndpoint: https://s3.cloudstorage.io
Region: eu-central-1
Authentication
CloudStorage uses S3-compatible access keys for API authentication. Every request must be signed using AWS Signature Version 4.
Obtaining credentials
When you create an account, your first access key pair is generated automatically. You can create up to 5 access keys from the dashboard or via the API.
# Create a new access key via the API
curl -X POST https://cloudstorage.io/api/keys \
-H "Content-Type: application/json" \
-H "Cookie: session=your-session-cookie" \
-d '{"name": "production-key"}'
# Response:
# {
# "accessKey": "CS...",
# "secretKey": "..."
# }Managing keys
| Method | Endpoint | Description |
|---|---|---|
GET | /api/keys | List all access keys |
POST | /api/keys | Create a new access key |
DELETE | /api/keys?id=xxx | Delete an access key |
Important: Secret keys are only shown once at creation time. Store them securely. If you lose a secret key, delete it and create a new one.
S3 Compatibility
CloudStorage supports the core S3 API operations. Our S3 proxy at https://s3.cloudstorage.io handles requests with automatic quota enforcement.
Supported operations
Bucket Operations
- CreateBucket
- DeleteBucket
- HeadBucket
- ListBuckets
Object Operations
- PutObject
- GetObject
- DeleteObject
- HeadObject
- ListObjectsV2
- CopyObject
Multipart Upload
- CreateMultipartUpload
- UploadPart
- CompleteMultipartUpload
- AbortMultipartUpload
Presigned
- Presigned GET
- Presigned PUT
Compatible tools
Any tool that supports a custom S3 endpoint will work. Verified compatibility includes:
Code Examples
Integrate CloudStorage into your application using any S3-compatible SDK.
Client setup
import boto3
s3 = boto3.client(
"s3",
endpoint_url="https://s3.cloudstorage.io",
region_name="eu-central-1",
aws_access_key_id="YOUR_ACCESS_KEY",
aws_secret_access_key="YOUR_SECRET_KEY",
)
# Upload a file
s3.upload_file("local-file.txt", "my-bucket", "remote-file.txt")
# Download a file
s3.download_file("my-bucket", "remote-file.txt", "downloaded.txt")
# List objects
response = s3.list_objects_v2(Bucket="my-bucket")
for obj in response.get("Contents", []):
print(obj["Key"], obj["Size"])Bucket Operations
Buckets are the top-level containers for your objects. You can create up to 10 buckets per account. Buckets can also be managed through the dashboard API.
Create a bucket
s3.create_bucket(
Bucket="my-new-bucket",
CreateBucketConfiguration={"LocationConstraint": "eu-central-1"},
)List buckets
response = s3.list_buckets()
for bucket in response["Buckets"]:
print(bucket["Name"], bucket["CreationDate"])Delete a bucket
# Bucket must be empty before deletion
aws s3 rb s3://my-bucket --endpoint-url https://s3.cloudstorage.io
# Force delete (removes all objects first)
aws s3 rb s3://my-bucket --force --endpoint-url https://s3.cloudstorage.ioObject Operations
Objects are the files stored in your buckets. There is no individual object size limit beyond your plan quota. Large files are automatically handled via multipart upload by most SDKs.
Put object
# Upload from file
s3.upload_file("local-file.txt", "my-bucket", "path/to/file.txt")
# Upload from bytes
s3.put_object(
Bucket="my-bucket",
Key="hello.txt",
Body=b"Hello, CloudStorage!",
ContentType="text/plain",
)Get object
# Download to file
s3.download_file("my-bucket", "path/to/file.txt", "local-file.txt")
# Read into memory
response = s3.get_object(Bucket="my-bucket", Key="hello.txt")
data = response["Body"].read()
print(data.decode("utf-8"))Delete object
s3.delete_object(Bucket="my-bucket", Key="path/to/file.txt")List objects
# List all objects
response = s3.list_objects_v2(Bucket="my-bucket")
for obj in response.get("Contents", []):
print(f"{obj['Key']:40s} {obj['Size']:>10d} bytes")
# List with prefix (like a directory)
response = s3.list_objects_v2(Bucket="my-bucket", Prefix="data/2025/")
for obj in response.get("Contents", []):
print(obj["Key"])
# Paginate through many objects
paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket="my-bucket"):
for obj in page.get("Contents", []):
print(obj["Key"])Presigned URLs
Generate temporary URLs that allow anyone to download or upload objects without needing credentials. Useful for sharing files, enabling direct browser uploads, or integrating with third-party services.
Generate a presigned download URL
# Generate a URL valid for 1 hour (3600 seconds)
url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": "my-bucket", "Key": "report.pdf"},
ExpiresIn=3600,
)
print(url)
# https://s3.cloudstorage.io/my-bucket/report.pdf?X-Amz-Algorithm=...Generate a presigned upload URL
# Generate a URL that allows uploading
url = s3.generate_presigned_url(
"put_object",
Params={
"Bucket": "my-bucket",
"Key": "uploads/user-file.jpg",
"ContentType": "image/jpeg",
},
ExpiresIn=600, # 10 minutes
)
# Client can then upload with:
# curl -X PUT -H "Content-Type: image/jpeg" --data-binary @photo.jpg "URL"Note: Presigned URLs respect your storage quota. Uploads via presigned URLs that would exceed your plan limit will be rejected with a 403 error.
Rate Limits
CloudStorage applies rate limits to ensure fair usage across all users.
| Operation Type | Limit | Window |
|---|---|---|
| PUT / POST / DELETE | 100 requests | per second |
| GET / HEAD | 300 requests | per second |
| LIST | 50 requests | per second |
| Dashboard API | 30 requests | per minute |
When rate limited, the API returns 429 Too Many Requests with a Retry-After header. Most S3 SDKs handle retry logic automatically.
Error Codes
CloudStorage returns standard S3-compatible error codes. Below are the most common ones you may encounter.
| HTTP Code | Error | Description |
|---|---|---|
| 400 | InvalidBucketName | Bucket name does not meet naming requirements. |
| 403 | AccessDenied | Invalid credentials or accessing another user's resources. |
| 403 | QuotaExceeded | Upload would exceed your plan's storage quota. Upgrade your plan or delete existing data. |
| 404 | NoSuchKey | The requested object does not exist. |
| 404 | NoSuchBucket | The specified bucket does not exist. |
| 409 | BucketAlreadyExists | A bucket with that name already exists in your account. |
| 409 | BucketNotEmpty | Cannot delete a bucket that still contains objects. |
| 429 | TooManyRequests | Rate limit exceeded. Retry after the duration in the Retry-After header. |
| 500 | InternalError | An unexpected error occurred. Retry with exponential backoff. |
Tip: All error responses include an XML body with Code, Message, and RequestId fields, matching the standard S3 error response format. Include the RequestId when contacting support.
Simple REST API
For simpler use cases where you don't need full S3 compatibility, CloudStorage offers a straightforward REST API. No SDK required -- just standard HTTP requests with an API key header.
Authentication
Authenticate requests using your access key and secret key in either of these formats:
# Option 1: X-API-Key header
curl https://cloudstorage.io/api/v1/files \
-H "X-API-Key: YOUR_ACCESS_KEY:YOUR_SECRET_KEY"
# Option 2: Bearer token
curl https://cloudstorage.io/api/v1/files \
-H "Authorization: Bearer YOUR_ACCESS_KEY:YOUR_SECRET_KEY"Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/v1/files | Upload a file (multipart form-data or raw body) |
GET | /api/v1/files | List files (?prefix=, ?limit=, ?bucket=) |
GET | /api/v1/files/{id} | Download a file |
GET | /api/v1/files/{id}?meta=true | Get file metadata only |
DELETE | /api/v1/files/{id} | Delete a file |
Upload a file
# Upload using multipart form-data (file field)
curl -X POST https://cloudstorage.io/api/v1/files \
-H "X-API-Key: YOUR_ACCESS_KEY:YOUR_SECRET_KEY" \
-F "[email protected]"
# Response:
# {
# "id": "abc123",
# "key": "photo.jpg",
# "bucket": "default",
# "size": 204800,
# "contentType": "image/jpeg",
# "createdAt": "2026-01-15T10:30:00Z"
# }List files
curl "https://cloudstorage.io/api/v1/files?prefix=photos/&limit=20&bucket=my-bucket" \
-H "X-API-Key: YOUR_ACCESS_KEY:YOUR_SECRET_KEY"
# Response:
# {
# "files": [
# { "id": "abc123", "key": "photos/cat.jpg", "size": 102400, "contentType": "image/jpeg", "updatedAt": "2026-01-15T10:30:00Z" },
# { "id": "def456", "key": "photos/dog.png", "size": 204800, "contentType": "image/png", "updatedAt": "2026-01-16T08:15:00Z" }
# ],
# "hasMore": false
# }Download and metadata
# Download a file by ID
curl https://cloudstorage.io/api/v1/files/abc123 \
-H "X-API-Key: YOUR_ACCESS_KEY:YOUR_SECRET_KEY" \
-o downloaded-file.jpgDelete a file
curl -X DELETE https://cloudstorage.io/api/v1/files/abc123 \
-H "X-API-Key: YOUR_ACCESS_KEY:YOUR_SECRET_KEY"
# Response:
# { "success": true }Image Transformations
Transform images on the fly via URL parameters. Resize, convert formats, apply effects, and optimize images without any preprocessing pipeline. A self-hosted alternative to Cloudinary or imgix.
Endpoint: /api/img/{bucket}/{path}?params
Cache: Transformed images are cached for 7 days.
Auto-format: Automatically serves WebP or AVIF when the browser supports it via Accept header detection.
Parameters
| Param | Description | Example |
|---|---|---|
| w | Width in pixels | w=400 |
| h | Height in pixels | h=300 |
| fit | Resize mode: fit, fill, cover, contain, crop, pad | fit=cover |
| format | Output format: webp, avif, jpeg, png | format=webp |
| q | Quality (1-100) | q=80 |
| blur | Gaussian blur radius | blur=10 |
| sharpen | Sharpen amount | sharpen=2 |
| rotate | Rotation in degrees | rotate=90 |
| gravity | Crop anchor: ce (center), sm (smart), no, so, ea, we | gravity=sm |
| dpr | Device pixel ratio multiplier | dpr=2 |
Examples
# Generate a 200x200 cover thumbnail with smart cropping
curl "https://cloudstorage.io/api/img/my-bucket/photos/hero.jpg?w=200&h=200&fit=cover&gravity=sm"
# Use in an HTML img tag:
# <img src="https://cloudstorage.io/api/img/my-bucket/photos/hero.jpg?w=200&h=200&fit=cover" />Webhooks
Configure webhook endpoints to receive real-time notifications when events happen in your storage account. Webhooks are delivered via HTTPS POST requests with JSON payloads.
Supported events
Object Events
object.createdobject.deletedobject.updated
Bucket Events
bucket.createdbucket.deleted
Quota Events
quota.warningquota.exceeded
Other Events
key.createdkey.revokedshare.createdshare.downloaded
API endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/webhooks | Create a webhook endpoint |
GET | /api/webhooks | List your webhooks |
PATCH | /api/webhooks | Update webhook (toggle active, change events) |
DELETE | /api/webhooks?id=xxx | Delete a webhook |
Create a webhook
curl -X POST https://cloudstorage.io/api/webhooks \
-H "Content-Type: application/json" \
-H "Cookie: session=your-session-cookie" \
-d '{
"url": "https://your-app.com/webhooks/cloudstorage",
"events": ["object.created", "object.deleted", "quota.warning"]
}'
# Response:
# {
# "id": "wh_abc123",
# "url": "https://your-app.com/webhooks/cloudstorage",
# "events": ["object.created", "object.deleted", "quota.warning"],
# "secret": "whsec_...",
# "active": true,
# "createdAt": "2026-01-15T10:30:00Z"
# }Payload format
Each webhook delivery is a POST request with a JSON body:
{
"event": "object.created",
"timestamp": "2026-01-15T10:30:00Z",
"data": {
"bucket": "my-bucket",
"key": "uploads/photo.jpg",
"size": 204800,
"contentType": "image/jpeg"
}
}Signature verification
Every webhook request includes an X-CloudStorage-Signature header containing an HMAC-SHA256 signature. Verify it using the secret returned when creating the webhook.
import crypto from "crypto";
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post("/webhooks/cloudstorage", (req, res) => {
const signature = req.headers["x-cloudstorage-signature"];
const isValid = verifyWebhook(JSON.stringify(req.body), signature, WEBHOOK_SECRET);
if (!isValid) return res.status(401).send("Invalid signature");
// Process event...
res.status(200).send("OK");
});Reliability: Failed deliveries are retried up to 3 times with exponential backoff. Webhooks are automatically disabled after 10 consecutive failures. Re-enable them from the dashboard or via the PATCH endpoint.
File Versioning
Time Machine for your files. Every time you overwrite a file, the previous version is automatically preserved. Browse version history, compare changes, and restore any previous version with a single click or API call.
Also available via the Time Machine UI in the dashboard -- select any file and browse its full version history.
API endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/versions | Upload a new version (multipart: file, bucket, key) |
GET | /api/versions?bucket=x | List all versioned files in a bucket |
GET | /api/versions?bucket=x&key=y | List all versions of a specific file |
PATCH | /api/versions | Restore a previous version |
Upload a new version
curl -X POST https://cloudstorage.io/api/versions \
-H "Cookie: session=your-session-cookie" \
-F "[email protected]" \
-F "bucket=my-bucket" \
-F "key=docs/report.pdf"
# Response:
# {
# "versionId": "ver_abc123",
# "key": "docs/report.pdf",
# "bucket": "my-bucket",
# "size": 524288,
# "versionNumber": 3,
# "createdAt": "2026-01-15T10:30:00Z"
# }List versions
# List all versions of a specific file
curl "https://cloudstorage.io/api/versions?bucket=my-bucket&key=docs/report.pdf" \
-H "Cookie: session=your-session-cookie"
# Response:
# {
# "versions": [
# { "versionId": "ver_abc123", "versionNumber": 3, "size": 524288, "createdAt": "2026-01-15T10:30:00Z", "isCurrent": true },
# { "versionId": "ver_def456", "versionNumber": 2, "size": 412672, "createdAt": "2026-01-10T14:20:00Z", "isCurrent": false },
# { "versionId": "ver_ghi789", "versionNumber": 1, "size": 307200, "createdAt": "2026-01-05T09:00:00Z", "isCurrent": false }
# ]
# }Restore a version
# Restore a previous version (makes it the current version)
curl -X PATCH https://cloudstorage.io/api/versions \
-H "Content-Type: application/json" \
-H "Cookie: session=your-session-cookie" \
-d '{ "versionId": "ver_def456" }'
# Response:
# {
# "success": true,
# "restoredVersion": "ver_def456",
# "newVersionNumber": 4
# }Retention policy
Max Versions
Up to 10 versions are kept per file by default. Oldest versions are pruned when the limit is exceeded.
Max Age
Versions older than 30 days are automatically cleaned up by default. Both limits are configurable.
Tip: Version storage counts toward your plan quota. Monitor usage in the dashboard to avoid unexpected overages.
Ready to get started?
Create your account and get S3 credentials in seconds.