Appearance
Rate Limiting
The MailShield API implements rate limiting to ensure fair usage and maintain service quality for all users.
Rate Limits
| Limit Type | Rate | Description |
|---|---|---|
| General | 60 requests/minute | Per token, applies to all endpoints |
| DNS Checks | 5 checks/minute | Per domain, for the /checks endpoint |
Rate Limit Headers
Every API response includes rate limit information in the headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1706270400| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per minute |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Handling Rate Limits
When you exceed the rate limit, you'll receive a 429 Too Many Requests response:
json
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Wait the number of seconds in the Retry-After header, then try again."
}
}The response includes a Retry-After header indicating how many seconds to wait:
Retry-After: 15Best Practices
Check headers proactively: monitor
X-RateLimit-Remainingto avoid hitting limitsWait before retrying: when rate limited, wait for the
Retry-Afterseconds, and back off further if it happens againCache responses: store and reuse data that doesn't change often
Use large pages: request
limit=100when paging through lists instead of making many small requests
Python Example with Retry
python
import time
import requests
def api_request(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limited. Waiting {retry_after} seconds...")
time.sleep(retry_after)
continue
return response
raise Exception("Max retries exceeded")Node.js Example with Retry
javascript
async function apiRequest(url, headers, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, { headers });
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Waiting ${retryAfter} seconds...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}DNS Check Rate Limits
The POST /domains/{id}/checks endpoint has a more restrictive rate limit (5 per minute per domain) because DNS checks are resource-intensive operations.
If you need to check multiple domains:
bash
# Good: Spread checks across domains
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/domain-1-id/checks
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/domain-2-id/checks
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/domain-3-id/checks
# Bad: Rapid checks on same domain
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/same-id/checks # OK
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/same-id/checks # OK
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/same-id/checks # OK
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/same-id/checks # OK
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/same-id/checks # OK
curl -X POST -H "Authorization: Bearer $MAILSHIELD_API_TOKEN" .../api/v1/domains/same-id/checks # Rate limited!Tips for Staying Under Limits
Let alerts come to you: instead of polling
/alerts, add a webhook, Slack or other notification channel so MailShield sends alerts as it raises themFetch data in bulk: page through lists with
limit=100Only run checks after a change: MailShield already checks every domain every 2 hours, so trigger a check when you've just changed DNS
Read stored results:
GET /domains/{id}returns the latest stored checks without running new ones