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 callMonitor 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');
}