Skip to content

Rate Limiting

The MyWarranties API implements rate limiting to ensure fair usage and protect against abuse.

Rate Limits

By User Role

RoleRequestsTime Window
Anonymous201 minute
CUSTOMER1001 hour
SUPPLIER2001 hour
RESELLER2001 hour
ADMIN5001 hour

By Endpoint Type

Endpoint TypeAdditional Limit
Authentication10 per 5 minutes
File Uploads20 per hour
Webhooks1000 per hour

Response Headers

Every API response includes rate limit information:

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1709568000
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when limit resets

Rate Limit Exceeded

When you exceed the rate limit, the API returns:

Status: 429 Too Many Requests

Response:

json
{
  "error": "RateLimitError",
  "message": "Too many requests. Please try again in 45 seconds.",
  "code": "RATE_LIMIT_EXCEEDED",
  "details": {
    "retry_after": 45,
    "limit": 100,
    "period": "1 hour"
  }
}

Headers:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 45
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1709568045

Implementation

Rate limiting is based on:

  • User ID (for authenticated requests)
  • IP Address (for anonymous requests)
  • Endpoint (different limits per endpoint type)

Best Practices

Respect Rate Limits

Always check response headers and respect limits:

typescript
async function makeRequest(url: string) {
  const response = await fetch(url, {
    headers: { 'Authorization': `Bearer ${token}` }
  });

  // Check rate limit headers
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
  const reset = parseInt(response.headers.get('X-RateLimit-Reset'));

  if (remaining < 10) {
    console.warn(`Only ${remaining} requests remaining`);
  }

  if (response.status === 429) {
    const retryAfter = parseInt(response.headers.get('Retry-After'));
    console.log(`Rate limited. Retry in ${retryAfter} seconds`);
    await sleep(retryAfter * 1000);
    return makeRequest(url); // Retry
  }

  return response.json();
}

Implement Exponential Backoff

typescript
async function fetchWithRetry(
  url: string,
  maxRetries: number = 3,
  baseDelay: number = 1000
) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);

      if (response.status === 429) {
        const retryAfter = parseInt(
          response.headers.get('Retry-After') || '60'
        );
        const delay = retryAfter * 1000;

        console.log(`Rate limited. Waiting ${retryAfter}s before retry ${i + 1}/${maxRetries}`);
        await sleep(delay);
        continue;
      }

      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;

      // Exponential backoff for other errors
      const delay = baseDelay * Math.pow(2, i);
      await sleep(delay);
    }
  }
}

Batch Requests

Instead of making many individual requests, batch them:

typescript
// Bad: 100 individual requests
for (const productId of productIds) {
  await fetch(`/api/products/${productId}`);
}

// Good: 1 batch request
const products = await fetch('/api/products', {
  method: 'POST',
  body: JSON.stringify({ ids: productIds })
});

Cache Responses

Cache API responses to reduce requests:

typescript
const cache = new Map();

async function getCachedProduct(id: number) {
  if (cache.has(id)) {
    return cache.get(id);
  }

  const product = await fetch(`/api/products/${id}`).then(r => r.json());
  cache.set(id, product);

  // Expire after 5 minutes
  setTimeout(() => cache.delete(id), 5 * 60 * 1000);

  return product;
}

Monitoring Rate Limits

Track Usage

typescript
class RateLimitTracker {
  private remaining: number = 100;
  private limit: number = 100;
  private resetAt: number = 0;

  updateFromHeaders(headers: Headers) {
    this.limit = parseInt(headers.get('X-RateLimit-Limit') || '100');
    this.remaining = parseInt(headers.get('X-RateLimit-Remaining') || '0');
    this.resetAt = parseInt(headers.get('X-RateLimit-Reset') || '0');
  }

  getPercentageRemaining(): number {
    return (this.remaining / this.limit) * 100;
  }

  getSecondsUntilReset(): number {
    return Math.max(0, this.resetAt - Math.floor(Date.now() / 1000));
  }

  shouldWait(): boolean {
    return this.remaining < 5; // Wait if less than 5 requests remaining
  }
}

Display to Users

typescript
function RateLimitIndicator({ tracker }: { tracker: RateLimitTracker }) {
  const percentage = tracker.getPercentageRemaining();
  const color = percentage > 50 ? 'green' : percentage > 20 ? 'yellow' : 'red';

  return (
    <div>
      <div style={{ color }}>
        API Quota: {tracker.remaining}/{tracker.limit}
      </div>
      {tracker.shouldWait() && (
        <div>
          Rate limit low. Resets in {tracker.getSecondsUntilReset()}s
        </div>
      )}
    </div>
  );
}

Increasing Limits

Contact support to request higher rate limits:

  • Email: support@my-warranties.nl
  • Subject: Rate Limit Increase Request
  • Include: Use case, expected request volume, account email

Webhook Rate Limits

Webhooks have separate, higher limits:

Webhook TypeLimit
Email Inbound1000/hour
General500/hour

Webhook rate limits are per source IP, not per user.

MyWarranties - Warranty Management System