Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.shingleai.com/llms.txt

Use this file to discover all available pages before exploring further.

The ShingleAI API enforces rate limits to ensure fair usage and maintain service stability for all users. Rate limits vary by subscription tier.

Rate Limits by Tier

TierRequests per MinuteBurst Limit
Free1015
Starter3045
Pro100150
EnterpriseCustomCustom
Burst limits allow temporary spikes above your per-minute limit. For example, a Pro tier user (100 req/min) can make up to 150 requests in a short burst. However, sustained traffic above your base rate limit will result in throttling. Burst capacity refills as your request rate drops below the limit.

Rate Limit Headers

Rate limit response headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After) are not yet emitted. Planned for a future release — until then, track your own request rate client-side and detect throttling by the 429 status code alone.

Handling Rate Limits

When you exceed your rate limit, the API returns a 429 Too Many Requests response:
{
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Please try again later."
    }
}
No Retry-After header is returned today, so use exponential backoff when retrying.

Implementing Rate Limit Handling

async function fetchWithRateLimit(
    url: string,
    options: RequestInit,
    attempt = 0,
): Promise<Response> {
    const response = await fetch(url, options);

    if (response.status === 429) {
        const backoffMs = Math.min(60_000, 1_000 * 2 ** attempt);
        console.log(`Rate limited. Waiting ${backoffMs}ms before retry...`);

        await new Promise(resolve => setTimeout(resolve, backoffMs));
        return fetchWithRateLimit(url, options, attempt + 1);
    }

    return response;
}

Best Practices

Instead of making requests as fast as possible, implement a queue that spreads requests evenly across your rate limit window.
class RequestQueue {
    private queue: Array<() => Promise<void>> = [];
    private processing = false;
    private requestsPerSecond: number;

    constructor(requestsPerMinute: number) {
        this.requestsPerSecond = requestsPerMinute / 60;
    }

    async add<T>(fn: () => Promise<T>): Promise<T> {
        return new Promise((resolve, reject) => {
            this.queue.push(async () => {
                try {
                    resolve(await fn());
                } catch (e) {
                    reject(e);
                }
            });
            this.process();
        });
    }

    private async process() {
        if (this.processing) return;
        this.processing = true;

        while (this.queue.length > 0) {
            const fn = this.queue.shift()!;
            await fn();
            await new Promise(r =>
                setTimeout(r, 1000 / this.requestsPerSecond)
            );
        }

        this.processing = false;
    }
}
When you receive a 429 response, don’t immediately retry. Implement exponential backoff starting at 1 second (e.g., 1s, 2s, 4s, 8s, capped at 60s).
Reduce API calls by caching responses that don’t change frequently. This is especially useful for reference data like contact lists or business details.
Where available, use batch endpoints to perform multiple operations in a single request instead of making separate calls.

Increasing Your Limits

If you consistently need higher rate limits:
  1. Upgrade your plan - Higher tiers include increased rate limits
  2. Contact sales - Enterprise plans include custom rate limits tailored to your needs

Upgrade Your Plan

View pricing and upgrade options
Last modified on April 19, 2026