Skip to content

Rate Limits & Performance

The FundlyHub API implements rate limiting to ensure fair usage and optimal performance for all users.

Rate Limit Tiers

Public / Discovery Requests

Unauthenticated API access (fundraiser browsing, search, categories)

Requests per minute: 300 Scope: Per IP

Authenticated Requests

With valid session (combined IP + User ID)

Requests per minute: 100 Scope: Per User + IP

Rate Limit Headers

The API includes rate limit information in response headers to help you track your usage:

http
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
X-RateLimit-Reset: 1672531200
Content-Type: application/json

{
  "data": [ /* response data */ ]
}

Handling Rate Limit Responses

When you exceed the rate limit, the API returns a 429 status code:

javascript
const API_BASE = 'https://api.fundlyhub.org/api/v1';

async function makeRateLimitedRequest() {
  try {
    const response = await fetch(`${API_BASE}/fundraisers`);
    
    // Check rate limit headers
    const remaining = response.headers.get('X-RateLimit-Remaining');
    const reset = response.headers.get('X-RateLimit-Reset');
    
    if (response.status === 429) {
      const resetDate = new Date(parseInt(reset) * 1000);
      console.error(`Rate limit exceeded. Resets at: ${resetDate}`);
      
      // Wait until reset time
      const waitTime = resetDate.getTime() - Date.now();
      await new Promise(resolve => setTimeout(resolve, waitTime));
      
      // Retry the request
      return makeRateLimitedRequest();
    }
    
    return response.json();
  } catch (error) {
    console.error('Request failed:', error);
  }
}

Performance Best Practices

Use Pagination

Reduce payload size and request count

javascript
// Good: Paginate large result sets
const response = await fetch(
  'https://api.fundlyhub.org/api/v1/fundraisers?limit=20&offset=0'
);

// Each page is a separate request toward your limit
const fundraisers = await response.json();

Implement Client-Side Caching

Cache responses to minimize API calls

javascript
// Cache API responses in memory
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedFundraisers() {
  const cacheKey = 'fundraisers:active';
  const cached = cache.get(cacheKey);
  
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }
  
  const response = await fetch(
    'https://api.fundlyhub.org/api/v1/fundraisers?status=active'
  );
  const data = await response.json();
  
  cache.set(cacheKey, { data, timestamp: Date.now() });
  return data;
}

Batch Requests When Possible

Reduce total request count by combining operations

Use query parameters to fetch related data in a single request:

javascript
// Good: Single request with includes
const response = await fetch(
  'https://api.fundlyhub.org/api/v1/fundraisers/123?include=category,owner'
);

// Returns fundraiser with category and owner data in one call

Monitor Your Rate Limits

Track usage to prevent hitting limits

javascript
// Track rate limit usage
function trackRateLimit(response) {
  const limit = response.headers.get('X-RateLimit-Limit');
  const remaining = response.headers.get('X-RateLimit-Remaining');
  const resetTime = response.headers.get('X-RateLimit-Reset');
  
  const percentUsed = ((limit - remaining) / limit) * 100;
  
  if (percentUsed > 80) {
    console.warn(`Rate limit usage: ${percentUsed.toFixed(1)}%`);
  }
  
  return {
    limit: parseInt(limit),
    remaining: parseInt(remaining),
    resetTime: new Date(parseInt(resetTime) * 1000)
  };
}

Retry Strategy

Implement exponential backoff when retrying failed requests:

javascript
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        // Rate limited - respect the reset time
        const reset = response.headers.get('X-RateLimit-Reset');
        const waitTime = (parseInt(reset) * 1000) - Date.now();
        
        if (attempt < maxRetries) {
          console.log(`Rate limited. Waiting ${waitTime}ms...`);
          await new Promise(resolve => setTimeout(resolve, waitTime));
          continue;
        }
      }
      
      if (response.ok) {
        return response.json();
      }
      
      // Other errors - exponential backoff
      if (attempt < maxRetries) {
        const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
        console.log(`Retrying in ${delay}ms... (attempt ${attempt}/${maxRetries})`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
  
  throw new Error('Max retries exceeded');
}

Built with VitePress