API Rate Limits
API Rate Limits
Section titled “API Rate Limits”Learn about mailiam’s API rate limiting system, quotas, and best practices for building resilient applications.
Overview
Section titled “Overview”mailiam implements comprehensive rate limiting to ensure fair usage and system stability. Rate limits apply at multiple levels:
- Per API Key - Limits per individual API key
- Per IP Address - Limits per client IP
- Per Endpoint - Specific limits for different endpoints
- Account-Level - Overall account quotas
Rate Limit Structure
Section titled “Rate Limit Structure”Standard Rate Limits
Section titled “Standard Rate Limits”| Plan | Requests/Hour | Requests/Minute | Burst Limit |
|---|---|---|---|
| Free | 1,000 | 50 | 100 |
| Pro | 25,000 | 500 | 1,000 |
| Enterprise | Custom | Custom | Custom |
Endpoint-Specific Limits
Section titled “Endpoint-Specific Limits”Different endpoints have different rate limits based on their resource intensity:
| Endpoint Category | Requests/Hour | Requests/Minute |
|---|---|---|
Form Submissions (/v1/{domain}/send) | 1,000 | 60 |
Instant Forms (/instant/forms) | 500 | 30 |
Collections (/collections) | 200 | 20 |
Domain Management (/domains) | 100 | 10 |
Analytics (/analytics) | 300 | 30 |
Admin Operations (/admin/*) | 50 | 5 |
Rate Limit Headers
Section titled “Rate Limit Headers”Every API response includes rate limit information in the headers:
HTTP/1.1 200 OKContent-Type: application/jsonX-RateLimit-Limit: 1000X-RateLimit-Remaining: 847X-RateLimit-Reset: 1672531200X-RateLimit-RetryAfter: 3600X-RateLimit-Scope: api-keyHeader Definitions
Section titled “Header Definitions”| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the time window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
X-RateLimit-RetryAfter | Seconds to wait before making another request |
X-RateLimit-Scope | Rate limit scope (api-key, ip, endpoint) |
HTTP 429 Responses
Section titled “HTTP 429 Responses”When rate limits are exceeded, the API returns a 429 Too Many Requests response:
{ "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "API rate limit exceeded", "details": { "limit": 1000, "remaining": 0, "reset_time": "2024-01-01T15:00:00Z", "retry_after": 3600, "scope": "api-key" } }, "documentation": "https://docs.mailiam.dev/api/rate-limits"}Rate Limit Error Codes
Section titled “Rate Limit Error Codes”| Code | Description | Action |
|---|---|---|
RATE_LIMIT_EXCEEDED | General rate limit hit | Wait and retry |
API_KEY_RATE_LIMIT | API key specific limit | Check key quotas |
IP_RATE_LIMIT | IP address limit hit | Change IP or wait |
ENDPOINT_RATE_LIMIT | Endpoint specific limit | Use different endpoint |
ACCOUNT_QUOTA_EXCEEDED | Account-level quota hit | Upgrade plan or wait |
Handling Rate Limits
Section titled “Handling Rate Limits”Exponential Backoff
Section titled “Exponential Backoff”Implement exponential backoff for resilient applications:
class mailiamAPI { constructor(apiKey) { this.apiKey = apiKey; this.baseUrl = 'https://api.mailiam.dev'; }
async request(endpoint, options = {}, retries = 3) { const url = `${this.baseUrl}${endpoint}`; const headers = { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', ...options.headers };
for (let attempt = 0; attempt <= retries; attempt++) { try { const response = await fetch(url, { ...options, headers });
// Check rate limit headers const remaining = parseInt(response.headers.get('X-RateLimit-Remaining')); const reset = parseInt(response.headers.get('X-RateLimit-Reset'));
if (response.status === 429) { if (attempt === retries) { throw new Error('Rate limit exceeded, max retries reached'); }
// Exponential backoff: 2^attempt * 1000ms const delay = Math.pow(2, attempt) * 1000; console.log(`Rate limited, retrying in ${delay}ms`); await this.sleep(delay); continue; }
if (!response.ok) { throw new Error(`API error: ${response.status}`); }
return await response.json(); } catch (error) { if (attempt === retries) throw error;
// Wait before retry const delay = Math.pow(2, attempt) * 1000; await this.sleep(delay); } } }
sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }}
// Usageconst mailiam = new mailiamAPI('mlm_sk_live_abc123...');
try { const response = await mailiam.request('/instant/forms', { method: 'POST', body: JSON.stringify({ name: 'Contact Form', email: 'contact@example.com' }) }); console.log('Form created:', response);} catch (error) { console.error('API request failed:', error);}Rate Limit-Aware Client
Section titled “Rate Limit-Aware Client”Build a client that proactively manages rate limits:
class RateLimitAwareClient { constructor(apiKey) { this.apiKey = apiKey; this.rateLimits = new Map(); this.queue = []; this.processing = false; }
async queueRequest(endpoint, options) { return new Promise((resolve, reject) => { this.queue.push({ endpoint, options, resolve, reject });
if (!this.processing) { this.processQueue(); } }); }
async processQueue() { this.processing = true;
while (this.queue.length > 0) { const request = this.queue.shift();
try { // Check if we should wait before making request await this.waitForRateLimit(request.endpoint);
const response = await this.makeRequest(request.endpoint, request.options);
// Update rate limit tracking this.updateRateLimits(response.headers);
request.resolve(await response.json()); } catch (error) { request.reject(error); } }
this.processing = false; }
async waitForRateLimit(endpoint) { const rateLimit = this.rateLimits.get(endpoint);
if (!rateLimit) return;
if (rateLimit.remaining <= 0) { const now = Date.now() / 1000; const waitTime = Math.max(0, rateLimit.reset - now) * 1000;
if (waitTime > 0) { console.log(`Waiting ${waitTime}ms for rate limit reset`); await this.sleep(waitTime); } } }
updateRateLimits(headers) { const limit = headers.get('X-RateLimit-Limit'); const remaining = headers.get('X-RateLimit-Remaining'); const reset = headers.get('X-RateLimit-Reset'); const scope = headers.get('X-RateLimit-Scope');
if (limit && remaining && reset) { this.rateLimits.set(scope, { limit: parseInt(limit), remaining: parseInt(remaining), reset: parseInt(reset) }); } }
async makeRequest(endpoint, options) { return fetch(`https://api.mailiam.dev${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', ...options.headers } }); }
sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }}Best Practices
Section titled “Best Practices”1. Monitor Rate Limits
Section titled “1. Monitor Rate Limits”Always check rate limit headers and log usage:
const logRateLimit = (headers) => { const limit = headers.get('X-RateLimit-Limit'); const remaining = headers.get('X-RateLimit-Remaining'); const reset = headers.get('X-RateLimit-Reset');
const resetTime = new Date(reset * 1000); const usage = ((limit - remaining) / limit * 100).toFixed(1);
console.log(`Rate limit usage: ${usage}% (${limit - remaining}/${limit})`); console.log(`Resets at: ${resetTime.toISOString()}`);
// Alert if usage is high if (remaining < limit * 0.1) { // Less than 10% remaining console.warn('Rate limit nearly exhausted!'); }};2. Batch Requests
Section titled “2. Batch Requests”Combine multiple operations into single requests when possible:
// Instead of multiple individual requestsconst forms = [];for (const formData of formList) { const form = await mailiam.request('/instant/forms', { method: 'POST', body: JSON.stringify(formData) }); forms.push(form);}
// Use batch operationsconst forms = await mailiam.request('/instant/forms/batch', { method: 'POST', body: JSON.stringify({ forms: formList })});3. Cache Responses
Section titled “3. Cache Responses”Cache API responses to reduce request volume:
class CachedmailiamClient { constructor(apiKey, cacheTimeout = 300000) { // 5 minutes default this.apiKey = apiKey; this.cache = new Map(); this.cacheTimeout = cacheTimeout; }
async get(endpoint) { const cacheKey = `GET:${endpoint}`; const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) { return cached.data; }
const response = await this.request(endpoint);
this.cache.set(cacheKey, { data: response, timestamp: Date.now() });
return response; }
// Cache analytics data (changes infrequently) async getAnalytics(timeRange) { return this.get(`/analytics?range=${timeRange}`); }}4. Use Webhooks Instead of Polling
Section titled “4. Use Webhooks Instead of Polling”Instead of repeatedly polling for updates, use webhooks:
// Instead of polling for form submissionsconst pollForSubmissions = async () => { while (true) { try { const submissions = await mailiam.request('/instant/forms/abc123/submissions'); // Process submissions await sleep(30000); // Wait 30 seconds } catch (error) { if (error.message.includes('rate limit')) { console.log('Rate limited, increasing poll interval'); await sleep(300000); // Wait 5 minutes } } }};
// Use webhooks instead (configured in mailiam dashboard)app.post('/webhooks/form-submitted', (req, res) => { // Process form submission webhook console.log('New submission:', req.body); res.status(200).send('OK');});Rate Limit Optimization
Section titled “Rate Limit Optimization”1. Request Prioritization
Section titled “1. Request Prioritization”Prioritize critical requests:
class PriorityQueue { constructor() { this.high = []; this.normal = []; this.low = []; }
add(request, priority = 'normal') { this[priority].push(request); }
next() { if (this.high.length) return this.high.shift(); if (this.normal.length) return this.normal.shift(); if (this.low.length) return this.low.shift(); return null; }
isEmpty() { return this.high.length === 0 && this.normal.length === 0 && this.low.length === 0; }}
const queue = new PriorityQueue();
// Add critical requests with high priorityqueue.add({ endpoint: '/domains/verify', options: { method: 'POST', body: domainData }}, 'high');
// Add routine requests with normal priorityqueue.add({ endpoint: '/analytics', options: { method: 'GET' }}, 'normal');2. Request Deduplication
Section titled “2. Request Deduplication”Avoid duplicate requests:
class DeduplicatedClient { constructor(apiKey) { this.apiKey = apiKey; this.pendingRequests = new Map(); }
async request(endpoint, options) { const key = `${options.method || 'GET'}:${endpoint}:${JSON.stringify(options.body || {})}`;
// Return existing promise if request is already pending if (this.pendingRequests.has(key)) { return this.pendingRequests.get(key); }
const promise = this.makeRequest(endpoint, options) .finally(() => { this.pendingRequests.delete(key); });
this.pendingRequests.set(key, promise); return promise; }
async makeRequest(endpoint, options) { // Actual API request implementation const response = await fetch(`https://api.mailiam.dev${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${this.apiKey}`, ...options.headers } });
if (!response.ok) { throw new Error(`API error: ${response.status}`); }
return response.json(); }}Monitoring and Alerting
Section titled “Monitoring and Alerting”1. Rate Limit Monitoring
Section titled “1. Rate Limit Monitoring”Track rate limit usage over time:
class RateLimitMonitor { constructor() { this.metrics = []; }
recordUsage(headers) { const timestamp = Date.now(); const limit = parseInt(headers.get('X-RateLimit-Limit')); const remaining = parseInt(headers.get('X-RateLimit-Remaining')); const used = limit - remaining; const usage = (used / limit) * 100;
this.metrics.push({ timestamp, limit, used, remaining, usage });
// Keep only last 1000 records if (this.metrics.length > 1000) { this.metrics = this.metrics.slice(-1000); }
// Alert on high usage if (usage > 80) { this.alert(`High rate limit usage: ${usage.toFixed(1)}%`); } }
getAverageUsage(minutes = 60) { const cutoff = Date.now() - (minutes * 60 * 1000); const recent = this.metrics.filter(m => m.timestamp > cutoff);
if (recent.length === 0) return 0;
const avgUsage = recent.reduce((sum, m) => sum + m.usage, 0) / recent.length; return avgUsage; }
alert(message) { console.warn(`[RATE LIMIT ALERT] ${message}`); // Send to monitoring system, Slack, etc. }}
const monitor = new RateLimitMonitor();
// Use with API clientconst response = await fetch(url, options);monitor.recordUsage(response.headers);2. Automated Scaling
Section titled “2. Automated Scaling”Automatically adjust request rates based on limits:
class AdaptiveRateClient { constructor(apiKey) { this.apiKey = apiKey; this.requestInterval = 1000; // Start with 1 request per second this.maxInterval = 10000; // Max 10 seconds between requests this.minInterval = 100; // Min 100ms between requests }
async request(endpoint, options) { const response = await this.makeRequest(endpoint, options); this.adjustInterval(response.headers); return response; }
adjustInterval(headers) { const remaining = parseInt(headers.get('X-RateLimit-Remaining')); const limit = parseInt(headers.get('X-RateLimit-Limit')); const usage = ((limit - remaining) / limit) * 100;
if (usage > 90) { // High usage - slow down significantly this.requestInterval = Math.min(this.requestInterval * 2, this.maxInterval); } else if (usage > 70) { // Moderate usage - slow down slightly this.requestInterval = Math.min(this.requestInterval * 1.5, this.maxInterval); } else if (usage < 30) { // Low usage - speed up this.requestInterval = Math.max(this.requestInterval * 0.8, this.minInterval); }
console.log(`Adjusted request interval to ${this.requestInterval}ms (usage: ${usage.toFixed(1)}%)`); }
async makeRequest(endpoint, options) { // Wait between requests await this.sleep(this.requestInterval);
const response = await fetch(`https://api.mailiam.dev${endpoint}`, { ...options, headers: { 'Authorization': `Bearer ${this.apiKey}`, ...options.headers } });
return response; }
sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }}Enterprise Rate Limits
Section titled “Enterprise Rate Limits”Custom Quotas
Section titled “Custom Quotas”Enterprise customers can request custom rate limits:
{ "enterprise_limits": { "requests_per_hour": 100000, "requests_per_minute": 2000, "burst_limit": 5000, "concurrent_connections": 100, "custom_endpoints": { "/custom/webhook": { "requests_per_minute": 1000 } } }}Dedicated Infrastructure
Section titled “Dedicated Infrastructure”Enterprise plans include:
- Dedicated API servers
- Custom rate limit configurations
- Priority support for rate limit adjustments
- Real-time monitoring dashboards
- Custom alerting thresholds
CLI Rate Limit Management
Section titled “CLI Rate Limit Management”Check Current Limits
Section titled “Check Current Limits”# View current API key rate limitsmailiam auth limits
# View account quotasmailiam account quotas
# Monitor real-time usagemailiam monitor rate-limits --liveOptimize CLI Usage
Section titled “Optimize CLI Usage”# Batch operations to reduce API callsmailiam domains setup --all
# Use local cachingmailiam config --cache-duration 300
# Parallel processing with rate limitingmailiam instant submissions --parallel 5 --rate-limit 10Troubleshooting Rate Limits
Section titled “Troubleshooting Rate Limits”Common Issues
Section titled “Common Issues”-
Unexpected 429 errors
- Check all active API keys and their usage
- Verify IP address isn’t hitting limits
- Review recent API call patterns
-
Inconsistent rate limits
- Different endpoints have different limits
- IP and API key limits are separate
- Time zone differences in reset times
-
High rate limit usage
- Implement request caching
- Use batch operations
- Switch to webhooks from polling
Debug Commands
Section titled “Debug Commands”# Check rate limit statuscurl -H "Authorization: Bearer mlm_sk_live_abc123..." \ https://api.mailiam.dev/rate-limits/status
# View recent rate limit hitsmailiam logs rate-limits --last-hour
# Test rate limitingmailiam test rate-limits --endpoint /instant/forms --count 100Getting Help
Section titled “Getting Help”Support Resources
Section titled “Support Resources”- Rate Limit Calculator: Estimate your needs
- Usage Dashboard: Real-time monitoring
- API Documentation: Complete endpoint reference
- Enterprise Support: Custom rate limit solutions
Contact Support
Section titled “Contact Support”Include this information when requesting rate limit help:
- API key ID (not the key itself)
- Current usage patterns
- Specific endpoints causing issues
- Business requirements for higher limits
- Technical architecture details
Proper rate limit management ensures reliable API access while maintaining optimal performance for all mailiam users.