Rate limits & quotas
Every request passes five checks in order: auth-failure IP bucket, per-key requests-per-minute, per-customer requests-per-minute, per-customer concurrent request cap, and per-customer daily bandwidth (upload and download tracked separately).
Default tiers
Your administrator sets your limits per customer; new customers default to the free tier. Talk to sales to raise any dimension.
Free tier Paid tier Requests / minute 60 600 Concurrent requests 5 25 Upload per day 1 GB 50 GB Download per day 10 GB 500 GB
Cost weights
Requests are billed against the per-minute counter by weight, so a batch of uploads consumes budget faster than the same number of metadata GETs.
GET single file / metadata / job status 1 List containers / list items / usage 3 Direct-URL upload/download URL minting 3 Upload / download / upload-session chunk 5 Copy or move job enqueue 10
A key rated at 60 requests/minute can therefore make 60 metadata GETs, 20 listings, 12 uploads, or 6 copy enqueues per minute — or any mix summing to 60.
Per-key overrides
Individual API keys can carry their own requestsPerMinute and concurrencyLimit — useful when one application should be more restrictive than the customer-wide cap. A request must pass BOTH the per-key bucket AND the per-customer bucket. Adding a second API key does not raise your customer-wide ceiling.
Denial responses
RPM denials return 429 RATE_LIMITED. Concurrency and bandwidth denials return 429 QUOTA_EXCEEDED with details.reason distinguishing the cause.
HTTP/1.1 429 Too Many Requests
Retry-After: 23
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Slow down and retry later.",
"details": {
"reason": "rpm",
"scope": "customer",
"limitPerMinute": 600,
"costWeight": 5
}
},
"requestId": "req_..."
}HTTP/1.1 429 Too Many Requests
Retry-After: 43200
{
"success": false,
"error": {
"code": "QUOTA_EXCEEDED",
"message": "The storage quota would be exceeded by this operation.",
"details": {
"reason": "bandwidth",
"direction": "up",
"limitBytesPerDay": 53687091200,
"usedBytes": 53690000000
}
},
"requestId": "req_..."
}Storage quotas
Your storage account has a byte quota; individual containers may carry an additional quota. Storage quotas are checked before an upload starts — uploads that would exceed the quota fail fast with QUOTA_EXCEEDED (413) and details.reason: "storage". Check your current usage at GET /api/v1/storage/usage.
Upload size limit
The synchronous upload limit is deployment-configured (default 4 MB on Vercel, where request bodies are capped by the platform). Oversized uploads return FILE_TOO_LARGE with the limit in error.details.maxUploadBytes. Use the resumable upload session flow for larger files (see the Files docs).
Direct-URL uploads and downloads
When you use POST /containers/{c}/direct-uploads or POST /files/{id}/download-url, bytes flow client ↔ storage provider without hitting the platform. The request that mints the URL still spends 3 cost units and reserves bandwidth against your daily cap right away — the declared upload size for uploads, the file's actual size for downloads. Cancelling a direct-upload session with DELETE releases the storage quota reservation; daily bandwidth accounting does not roll back because the URL may already have been used.
Client guidance
Respect Retry-After and back off exponentially on 429. A well-behaved client that starts at 1 s and doubles on each 429 (capped at 30 s) will not accumulate a retry-storm and will typically stabilize below the limit within three retries.
For batch workloads, cap client concurrency at or below your customer's concurrency limit — going higher just wastes round-trips on QUOTA_EXCEEDED reason=concurrency.
Backend throttling
The storage backend applies its own throttling. The platform retries transient throttling internally; when throttling persists, you receive STORAGE_THROTTLED (429) with a Retry-After header. Back off accordingly.