Understand rate limiting policies, monitor your usage with response headers, and implement best practices for optimal API performance.
1,000
requests per hour
5,000
requests per hour
25,000+
requests per hour
The 3PL SHIP API uses a sliding window rate limiting algorithm to ensure fair usage and optimal performance for all users. Rate limits are applied per API key and configured based on your account tier.
Rate Limit Tracking
Rate limits track requests across three time windows: per minute, per hour, and per day. Each API key has its own configured limits stored in the api_keys table.
Every API response includes headers that help you monitor your rate limit status:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1704974400
Retry-After: 3600Maximum number of requests allowed in the current time window for your API key.
Number of requests remaining in the current time window before hitting the limit.
Unix timestamp (seconds since epoch) when the rate limit window resets.
Number of seconds to wait before making another request (included in 429 RATE_LIMIT_EXCEEDED responses).
When you exceed the rate limit, the API returns a 429 Too Many Requests status code with error code RATE_LIMIT_EXCEEDED. Implement exponential backoff to handle these gracefully:
const apiKey = 'zl_live_xxxxx';
async function makeRequest(url, options, retries = 3) {
try {
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${apiKey}`,
...options.headers
}
});
const result = await response.json();
if (response.status === 429) {
const retryAfter = parseInt(
response.headers.get('Retry-After') || '60'
);
const resetTime = response.headers.get(
'X-RateLimit-Reset'
);
console.log(`Rate limited. Reset at: ${resetTime}`);
if (retries > 0) {
await sleep(retryAfter * 1000);
return makeRequest(url, options, retries - 1);
}
throw new Error('Rate limit exceeded');
}
// Log current rate limit status
console.log(`Remaining: ${response.headers.get(
'X-RateLimit-Remaining'
)}`);
return result;
} catch (error) {
throw error;
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}import requests
import time
api_key = 'zl_live_xxxxx'
def make_request(url, max_retries=3):
retries = 0
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
while retries < max_retries:
response = requests.get(url, headers=headers)
result = response.json()
if response.status_code == 429:
retry_after = int(
response.headers.get('Retry-After', 60)
)
reset_time = response.headers.get(
'X-RateLimit-Reset'
)
print(f"Rate limited until: {reset_time}")
time.sleep(retry_after)
retries += 1
continue
# Log current rate limit status
remaining = response.headers.get(
'X-RateLimit-Remaining'
)
print(f"Remaining requests: {remaining}")
return result
raise Exception("Max retries exceeded")Always check rate limit headers and implement proactive throttling before hitting the limit.
Cache responses locally to reduce API calls for frequently accessed data.
Subscribe to webhooks instead of polling endpoints for real-time updates.
Use batch endpoints when available to reduce the number of API calls.
Don't make excessive parallel requests as they count against your limit simultaneously.
Always respect 429 responses and implement proper retry logic with backoff.
Enterprise plans include custom rate limits tailored to your business needs.