Rate Limits
OpenBoxes Lift enforces rate limits on API requests to ensure fair usage and platform stability. Limits are applied per tenant and vary by subscription tier.
Limits by Tier
| Tier | Requests per Hour | Requests per Second (burst) | Use Case |
|---|---|---|---|
| Shared | 1,000 | 5 | Small teams, light integrations |
| Dedicated | 25,000 | 50 | Production integrations, automated workflows |
| Enterprise | Custom | Custom | High-volume, mission-critical systems |
Limits apply across all API endpoints combined. There is no per-endpoint breakdown -- a request to /api/products and a request to /api/stockMovements both count toward the same hourly quota.
Rate Limit Headers
Every API response includes headers indicating your current rate limit status:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1700003600
Content-Type: application/json
| Header | Type | Description |
|---|---|---|
X-RateLimit-Limit |
integer | Your total requests allowed per hour |
X-RateLimit-Remaining |
integer | Requests remaining in the current window |
X-RateLimit-Reset |
integer | Unix timestamp when the window resets |
Checking Your Limits
Read the rate limit headers from any API response:
curl -s -D - -b cookies.txt \
"https://acme.openboxes.cloud/openboxes/api/products?max=1" \
-o /dev/null 2>&1 | grep -i "x-ratelimit"
Example output:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 612
X-RateLimit-Reset: 1700003600
Handling 429 Responses
When you exceed the rate limit, the API returns HTTP 429 Too Many Requests:
{
"errorCode": 429,
"errorMessage": "Rate limit exceeded. Try again in 847 seconds.",
"retryAfter": 847
}
The response includes a Retry-After header indicating how many seconds to wait:
HTTP/1.1 429 Too Many Requests
Retry-After: 847
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700003600
Implementing Retry Logic
Always implement exponential backoff when encountering rate limits:
#!/bin/bash
# Simple retry with backoff
MAX_RETRIES=3
RETRY_COUNT=0
make_request() {
response=$(curl -s -w "\n%{http_code}" -b cookies.txt \
"https://acme.openboxes.cloud/openboxes/api/products?max=25&offset=$1")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -n -1)
if [ "$http_code" = "429" ]; then
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -le $MAX_RETRIES ]; then
wait_time=$((2 ** RETRY_COUNT * 10))
echo "Rate limited. Waiting ${wait_time}s before retry $RETRY_COUNT..."
sleep $wait_time
make_request "$1"
else
echo "Max retries exceeded."
exit 1
fi
else
echo "$body"
fi
}
make_request 0
Best Practices
Minimize Unnecessary Requests
Cache responses that do not change frequently:
# Bad: fetching all locations on every sync cycle
# (locations rarely change, burns through your quota)
while true; do
curl -b cookies.txt ".../api/locations"
sleep 60
done
# Good: cache locations, refresh once per hour
curl -b cookies.txt ".../api/locations" > /tmp/locations_cache.json
# Use cached data for the next hour
Use Pagination Efficiently
Fetch data in reasonable batch sizes instead of making many small requests:
# Bad: fetching one product at a time (100 requests for 100 products)
for id in $product_ids; do
curl -b cookies.txt ".../api/products/$id"
done
# Good: fetch in batches (4 requests for 100 products)
for offset in 0 25 50 75; do
curl -b cookies.txt ".../api/products?max=25&offset=$offset"
done
Monitor Your Usage
Track the X-RateLimit-Remaining header to detect when you are approaching your limit:
remaining=$(curl -s -D - -b cookies.txt \
"https://acme.openboxes.cloud/openboxes/api/products?max=1" \
-o /dev/null 2>&1 | grep -i "x-ratelimit-remaining" | tr -d '\r' | cut -d' ' -f2)
if [ "$remaining" -lt 100 ]; then
echo "WARNING: Only $remaining API requests remaining this hour"
fi
Spread Requests Over Time
Avoid bursting all requests at the start of each hour. Distribute your API calls evenly:
# Bad: sync everything at the top of the hour
0 * * * * /scripts/full_sync.sh # 500 requests in 2 minutes
# Good: stagger sync tasks across the hour
0 * * * * /scripts/sync_products.sh # ~50 requests
15 * * * * /scripts/sync_inventory.sh # ~100 requests
30 * * * * /scripts/sync_orders.sh # ~75 requests
45 * * * * /scripts/sync_movements.sh # ~80 requests
Re-use Sessions
Each login request counts against your rate limit. Authenticate once and re-use the session cookie for all subsequent requests. See Authentication for details.
Upgrading Your Limit
If your integration needs exceed your current tier's limits:
| Current Tier | Upgrade Path |
|---|---|
| Shared (1,000/hr) | Upgrade to Dedicated for 25x the capacity |
| Dedicated (25,000/hr) | Contact sales for Enterprise with custom limits |
| Enterprise | Adjust limits through your account team |
Visit the Pricing page or contact your account manager to discuss tier upgrades.
Frequently Asked Questions
Do rate limits apply to the OpenBoxes web UI?
No. Rate limits only apply to API requests (calls to /openboxes/api/*). Normal browser usage of the OpenBoxes application is not rate-limited.
Are login requests counted?
Yes. POST requests to /api/login count toward your hourly limit. This is another reason to re-use sessions rather than authenticating on every request.
What happens if I consistently hit the limit?
Persistent rate limit violations may indicate that you need a higher tier. Lift does not suspend accounts for hitting rate limits, but sustained 429 responses will degrade your integration's performance.
Can I request a temporary limit increase? Enterprise tier customers can request temporary limit increases for data migration or one-time bulk operations through their account team.