Rate Limits
The ShipOS API implements rate limiting to ensure fair usage and maintain service reliability for all users. This guide explains how rate limits work, the different tiers available, and best practices for handling rate limit responses.
How Rate Limiting Works
- Window Duration: Rate limits are calculated per 60-second window
- Per API Key: Each API key has its own rate limit counter
- Shared Across Endpoints: The rate limit applies to all API endpoints collectively
- Tier-Based: Different rate limit tiers are available based on your needs
Rate Limit Tiers
ShipOS offers six rate limit tiers to accommodate different usage patterns:
| Tier | Requests per Minute | Requests per Second |
|---|---|---|
| Tier 1 | 30 | 0.5 |
| Tier 2 | 60 | 1 |
| Tier 3 | 120 | 2 |
| Tier 4 | 240 | 4 |
| Tier 5 | 600 | 10 |
| Tier 6 | 1,200 | 20 |
Your API key's rate limit tier determines how many requests you can make. Contact support to upgrade your tier if needed.
Rate Limit Headers
Every API response includes headers that provide information about your current rate limit status:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 543
X-RateLimit-Reset: 1706012400Header Descriptions
| Header | Description |
|---|---|
| X-RateLimit-Limit | Total number of requests allowed in the current window |
| X-RateLimit-Remaining | Number of requests remaining in the current window |
| X-RateLimit-Reset | Unix timestamp (in seconds) when the rate limit window resets |
Rate Limit Errors
When you exceed your rate limit, the API returns a 429 Too Many Requests status with an error response:
{
"type": "urn:cybership:error:rate-limit",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "Rate limit exceeded. You have made too many requests in a short period of time. (Reference this ID for support: 8f7e6d5c4b3a2918)",
"limit": 600,
"remaining": 0,
"reset_at": "2024-01-23T10:20:00Z",
"retry_after": 45
}The response also includes a Retry-After header indicating how many seconds to wait before retrying:
Retry-After: 45Best Practices
1. Monitor Rate Limit Headers
Always check the rate limit headers in responses to track your usage:
const response = await fetch(`${API_BASE}/shipos/orders`, {
headers: {
'X-Access-Token': API_KEY,
},
});
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset_at = response.headers.get('X-RateLimit-Reset');
console.log(`Requests remaining: ${remaining}`);
console.log(`Reset at: ${new Date(reset_at * 1000).toISOString()}`);2. Implement Exponential Backoff
When you receive a 429 error, implement exponential backoff with jitter:
async function makeRequestWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
const retryAfter = parseInt(response.headers.get('Retry-After')) || 60;
const jitter = Math.random() * 1000; // 0-1 second jitter
const delay = (retryAfter * 1000) + jitter;
console.log(`Rate limited. Waiting ${delay}ms before retry ${i + 1}/${maxRetries}`);
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Max retries exceeded');
}3. Spread Requests Over Time
Instead of bursting requests, spread them evenly:
// Bad: Burst of requests
for (const order of orders) {
await processOrder(order); // May hit rate limit
}
// Good: Spread requests with delays
for (const order of orders) {
await processOrder(order);
await new Promise(resolve => setTimeout(resolve, 500)); // 2 req/sec for Tier 1
}4. Use Webhooks for Real-Time Updates
Instead of polling endpoints repeatedly, use webhooks to receive real-time updates about order status changes, inventory updates, and other events.
5. Batch Operations
Where possible, use batch endpoints to reduce the number of API calls:
- Use bulk order retrieval instead of fetching orders one by one
- Create multiple packages in a single fulfillment session
- Update multiple inventory items in one request
Handling Rate Limits in Production
Example Rate Limit Handler
class ShipOSApiClient {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
this.requestQueue = [];
this.processing = false;
}
async request(method, path, body = null) {
return new Promise((resolve, reject) => {
this.requestQueue.push({ method, path, body, resolve, reject });
this.processQueue();
});
}
async processQueue() {
if (this.processing || this.requestQueue.length === 0) {
return;
}
this.processing = true;
while (this.requestQueue.length > 0) {
const { method, path, body, resolve, reject } = this.requestQueue.shift();
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
headers: {
'X-Access-Token': this.apiKey,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : null,
});
if (response.status === 429) {
// Put the request back in the queue
this.requestQueue.unshift({ method, path, body, resolve, reject });
// Wait for rate limit reset
const retryAfter = parseInt(response.headers.get('Retry-After')) || 60;
console.log(`Rate limited. Pausing queue for ${retryAfter} seconds`);
await new Promise(res => setTimeout(res, retryAfter * 1000));
continue;
}
const data = await response.json();
if (!response.ok) {
reject(new Error(data.detail || 'API request failed'));
} else {
resolve(data);
}
// Respect rate limits by adding delays based on remaining quota
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
const limit = parseInt(response.headers.get('X-RateLimit-Limit'));
if (remaining < limit * 0.2) {
// Slow down when approaching limit
await new Promise(res => setTimeout(res, 1000));
}
} catch (error) {
reject(error);
}
}
this.processing = false;
}
}Frequently Asked Questions
Need Higher Rate Limits?
If your use case requires higher rate limits than Tier 6 provides, please contact support to discuss enterprise options. We can accommodate high-volume integrations with custom rate limiting solutions.
MCP for AI Agents
Connect Claude Desktop, ChatGPT web, Codex, and other MCP clients to Cybership
Fulfill an Order
This guide walks you through the complete process of fulfilling orders using the ShipOS API. The fulfillment process involves multiple steps to ensure data integrity and proper inventory management.