Skip to content

Rate Limits

Spamidate enforces three types of limits to ensure fair usage and system stability.

TypeWindowPurpose
Per-minuteRolling 60 secondsPrevent burst abuse
Per-dayCalendar day (UTC)Daily usage cap
Per-monthBilling cycleTotal plan quota
TierPer MinutePer DayPer MonthGrace Period
Free10100100None
Hobby502,0002,000None
Growth10010,00010,00020%
Pro50050,00050,00020%
Business1,000200,000200,00020%
Scale2,500500,000500,00020%
EnterpriseCustomCustomCustom20%
0%────────80%────────100%────────120%
│ │ │
│ │ └── Hard stop
│ └── Grace period starts
└── Normal usage
Usage RangeBehavior
0-80%Normal operation
80-100%Warning headers sent
100-120%Grace period (requests still work)
>120%Hard stop until next cycle

Free and Hobby tiers stop immediately at 100% quota—no grace period. Upgrade to Growth for the buffer.

Every response includes rate limit information:

X-RateLimit-Limit-Minute: 100
X-RateLimit-Limit-Day: 10000
X-RateLimit-Remaining: 88
X-RateLimit-Reset: 2024-01-15T10:31:00.000Z
X-RateLimit-Used-Month: 4523
X-RateLimit-Limit-Month: 10000

Status: 429 Too Many Requests

Headers:

Retry-After: 45
X-RateLimit-Remaining: 0

Body:

{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"details": {
"limit": 100,
"window": "minute",
"retryAfter": 45
}
}
}

The SDK handles rate limits automatically:

import { Spamidate, RateLimitError } from '@spamidate/sdk';
const client = new Spamidate({
apiKey: process.env.SPAMIDATE_API_KEY,
retries: 3, // Automatic retry on rate limit
});
// SDK waits for Retry-After automatically
const result = await client.validate(email);
async function validateWithRetry(email: string): Promise<Result> {
const response = await fetch('https://api.spamidate.com/validate', {
method: 'POST',
headers: {
'X-API-Key': process.env.SPAMIDATE_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
await new Promise(r => setTimeout(r, retryAfter * 1000));
return validateWithRetry(email);
}
return response.json();
}

One API call for up to 100 emails:

// Instead of 100 separate calls
const results = await client.validateBatch(emails.slice(0, 100));

Validation results are stable—cache for 24 hours:

const cache = new Map();
async function validate(email: string) {
const key = email.toLowerCase();
if (cache.has(key)) return cache.get(key);
const result = await client.validate(email);
cache.set(key, result);
return result;
}

Skip expensive checks when speed matters:

// Real-time form validation
const quick = await client.validate(email, { quickMode: true });
// Background processing - full validation
const full = await client.validate(email);
const unique = [...new Set(emails.map(e => e.toLowerCase()))];
const results = await client.validateBatch(unique);

View real-time usage at spamidate.com/dashboard.

const usage = await client.getUsage();
console.log(`${usage.quota.percentage}% used`);
console.log(`${usage.quota.remaining} remaining`);
console.log(`${usage.period.daysRemaining} days left`);

Do cached results count against quota? No. Server-side caching is free—each unique validation counts once.

Does batch count as 1 or 100 requests? Each email counts toward quota, but it’s one rate limit request.

Can I get a temporary quota increase? Enterprise plans can request increases. Contact support.

Do failed validations count? Yes. Any processed request counts (even invalid emails).

How do I check quota without using it? Use GET /api/usage—this endpoint is free.