Rate Limits & Errors
Understand SentinMail API rate limits, error codes, and best practices for handling failures
Rate Limits
SentinMail enforces rate limits to protect the platform and ensure fair usage. Limits are applied per API key or per IP address (for public endpoints).
| Scope | Limit | Applies To |
|---|---|---|
| Authentication | 5 requests/min | Login, register, token refresh |
| Public subscribe | 3 requests/min | Public subscribe endpoint (per IP) |
| Email tracking | 60 requests/min | Open/click tracking pixels |
| General API | Based on plan | All authenticated endpoints |
When You're Rate Limited
The API returns 429 Too Many Requests:
json
1{2 "detail": "Request was throttled. Expected available in 45 seconds."3}How to handle it:
- Read the
Retry-Afterheader (if present) for the wait time - Implement exponential backoff in your client
- Queue requests and process them at a sustainable rate
Example: Retry with Backoff
javascript
1async function apiCall(url, options, maxRetries = 3) {2 for (let attempt = 0; attempt < maxRetries; attempt++) {3 const res = await fetch(url, options);4 5 if (res.status !== 429) return res;6 7 const retryAfter = res.headers.get('Retry-After');8 const waitMs = retryAfter9 ? parseInt(retryAfter) * 100010 : Math.pow(2, attempt) * 1000;11 12 await new Promise((resolve) => setTimeout(resolve, waitMs));13 }14 15 throw new Error('Max retries exceeded');16}Error Codes
Standard HTTP Status Codes
| Status | Meaning | Common Cause |
|---|---|---|
200 | Success | Request completed |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid request body, missing required fields |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Plan limit reached, insufficient permissions |
404 | Not Found | Resource doesn't exist or doesn't belong to your company |
429 | Too Many Requests | Rate limit exceeded |
500 | Server Error | Something went wrong on our end |
Error Response Format
All errors return a JSON body with a detail field:
json
1{2 "detail": "Human-readable error message."3}Some validation errors include field-level detail:
json
1{2 "email": ["This field is required."],3 "template": ["Invalid pk \"bad-uuid\" - object does not exist."]4}Common Errors and Solutions
401 — Invalid API Key
json
1{"detail": "Invalid API key."}Check:
- Is the
X-API-Keyheader present? - Is the key copied correctly (no extra whitespace)?
- Has the key expired?
- Was the key deleted from the dashboard?
403 — Plan Limit Reached
json
1{"detail": "Subscriber limit reached for your plan."}json
1{"detail": "Email quota exceeded for your plan."}Solutions:
- Check your current usage:
GET /api/companies/<id>/plan/ - Upgrade your subscription plan
- Wait for your quota to reset (monthly)
- Clean up unused subscribers
404 — Resource Not Found
json
1{"detail": "Not found."}Check:
- Does the resource ID belong to the company associated with your API key?
- Was the resource deleted?
- Is the UUID formatted correctly?
400 — Validation Error
json
1{"email": ["Enter a valid email address."]}Check:
- Are all required fields present?
- Are UUIDs valid and correctly formatted?
- Is the
Content-Type: application/jsonheader set?
Best Practices
- Always check status codes — don't assume success; check
res.okorres.status - Implement retry logic — use exponential backoff for
429and5xxerrors - Don't retry
4xxerrors — these are client errors; fix the request before retrying - Log API responses — store error responses for debugging
- Monitor your usage — check
GET /api/companies/<id>/plan/periodically to avoid hitting limits unexpectedly - Use idempotent operations — subscribing the same email twice is safe (returns success both times)
Pagination
All list endpoints return paginated responses (20 items per page):
json
1{2 "count": 2500,3 "next": "https://api.sentinmail.app/api/emails/subscribers/?page=2",4 "previous": null,5 "results": [...]6}Iterate through pages by following the next URL until it's null.
rate-limitserrorsapitroubleshooting