Skip to content

Rate Limits ​

Understanding and working within API rate limits.

Rate Limit Overview ​

Each API token is limited to 60 requests per minute.

This applies to all endpoints and is designed to:

  • Ensure fair usage across all stores
  • Protect API stability
  • Prevent abuse

Rate Limit Headers ​

Every response includes rate limit information:

HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in window
X-RateLimit-ResetUnix timestamp when window resets

Example Headers ​

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 55
X-RateLimit-Reset: 1640000060

When Rate Limited ​

If you exceed the limit, you'll receive a 429 Too Many Requests response:

json
{
  "success": false,
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Retry after 45 seconds",
  "retry_after": 45
}

The retry_after field indicates seconds until you can retry.

Best Practices ​

1. Monitor Headers ​

Track your remaining requests to avoid hitting limits:

javascript
function checkRateLimit(headers) {
    const remaining = parseInt(headers['x-ratelimit-remaining']);
    const reset = parseInt(headers['x-ratelimit-reset']);

    if (remaining < 10) {
        console.warn(`Low rate limit: ${remaining} requests remaining`);
    }

    return { remaining, reset };
}

2. Implement Backoff ​

When rate limited, wait before retrying:

javascript
async function requestWithBackoff(endpoint) {
    const response = await client.get(endpoint);

    if (response.status === 429) {
        const retryAfter = response.data.retry_after || 60;
        console.log(`Rate limited. Waiting ${retryAfter}s...`);
        await sleep(retryAfter * 1000);
        return requestWithBackoff(endpoint);
    }

    return response;
}

3. Batch Operations ​

Instead of many small requests, batch where possible:

javascript
// Instead of this:
for (const id of productIds) {
    await client.get(`/products/${id}`);  // 100 requests
}

// Do this:
const response = await client.get('/products');  // 1 request
const products = response.data.data;

4. Cache Responses ​

Cache data that doesn't change frequently:

javascript
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getProductCached(id) {
    const key = `product:${id}`;
    const cached = cache.get(key);

    if (cached && Date.now() < cached.expiry) {
        return cached.data;
    }

    const response = await client.get(`/products/${id}`);
    cache.set(key, {
        data: response.data,
        expiry: Date.now() + CACHE_TTL
    });

    return response.data;
}

5. Use Webhooks ​

Instead of polling for updates, use webhooks:

javascript
// Instead of polling every minute:
setInterval(async () => {
    const orders = await client.get('/orders?status=pending');
    processOrders(orders);
}, 60000);

// Use webhooks - no rate limit concerns:
app.post('/webhooks', (req, res) => {
    if (req.body.event === 'order.paid') {
        processOrder(req.body.data);
    }
    res.sendStatus(200);
});

6. Spread Requests ​

If you need many requests, spread them over time:

javascript
async function fetchAllProducts() {
    const products = [];
    let page = 1;

    while (true) {
        const response = await client.get(`/products?page=${page}&per_page=100`);
        products.push(...response.data.data);

        if (page >= response.data.meta.last_page) {
            break;
        }

        page++;
        await sleep(1000); // 1 second between requests
    }

    return products;
}

Increasing Limits ​

Need higher rate limits? Contact support to discuss options for high-volume integrations.

Testing ​

Use the rate limit headers to test your handling:

  1. Make requests until X-RateLimit-Remaining is low
  2. Verify your code handles 429 responses correctly
  3. Confirm backoff logic waits appropriate time

Built for game developers, by game developers.