Rate limits
Brixus365 enforces two kinds of limits: per-minute request limits (preview accounts only) and monthly send quotas (all accounts). Both return HTTP 429 with a Retry-After header. See Errors for the full error envelope shape.
Response headers
On preview-account requests, every API response includes rate-limit headers:
| Header | Type | Description |
|---|---|---|
X-RateLimit-Limit | integer | Maximum requests allowed in the current window. |
X-RateLimit-Remaining | integer | Requests remaining before you hit the limit. |
X-RateLimit-Reset | unix timestamp | UTC timestamp when the current window resets. |
X-RateLimit-Window | integer | Window duration in seconds. |
These headers reflect the per-minute window. Full accounts do not enforce per-minute limits and do not receive these headers.
Send limits
| Account type | Per-minute | Daily | Monthly |
|---|---|---|---|
Preview account (bx_test_* key) | 10 requests | 50 emails | 1,500 emails |
| Free account | — | — | 9,000 emails |
| Paid plans | — | — | See Pricing |
Preview accounts are created via the sign-up API for quick evaluation. Create a free account to lift the per-minute and daily limits.
Per-minute rate limit
Preview accounts are limited to 10 requests per minute per API key. When exceeded:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 47
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1746458820
X-RateLimit-Window: 60
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Try again in up to 1 minute.",
"type": "rate_limit_error",
"retry_after_seconds": 47,
"details": {
"limit": 10,
"window_seconds": 60
}
}
}
Wait the value of Retry-After (or error.retry_after_seconds) before retrying. The window is 60 seconds; retrying immediately returns another 429.
Daily send limit
Preview accounts are limited to 50 emails per day. Once the daily limit is reached, wait for the daily reset or create a free account to lift the limit.
{
"error": {
"code": "daily_limit_exceeded",
"message": "Daily limit of 50 emails reached. Upgrade to send more.",
"type": "rate_limit_error",
"upgrade_url": "https://brixus365.com/pricing",
"details": {
"limit": 50,
"used": 50
}
}
}
Monthly send quotas
When the monthly limit is reached, the API returns 429 regardless of account type:
{
"error": {
"code": "monthly_limit_exceeded",
"message": "Monthly limit of 9000 emails reached.",
"type": "rate_limit_error",
"upgrade_url": "https://brixus365.com/pricing",
"details": {
"limit": 9000,
"used": 9000
}
}
}
Monthly quotas reset on the first day of each calendar month.
Handling rate limits in code
Honour Retry-After for per-minute limits; distinguish quota exhaustion (which requires a plan upgrade, not a wait):
import time
import requests
def send_with_retry(api_key, payload, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
"https://app.brixus365.com/api/v1/emails/send",
headers={"X-API-Key": api_key},
json=payload,
)
if resp.status_code != 429:
resp.raise_for_status()
return resp.json()
err = resp.json().get("error", {})
code = err.get("code")
if code in ("daily_limit_exceeded", "monthly_limit_exceeded"):
raise RuntimeError(
f"Send limit reached — upgrade at {err.get('upgrade_url')}"
)
wait = int(resp.headers.get("Retry-After", 60))
if attempt < max_retries - 1:
time.sleep(wait)
continue
raise RuntimeError("Rate limit retries exhausted")
What’s next
| You want to… | Go to |
|---|---|
| See every error code with description and suggested action | Error codes |
| Understand the error envelope | Errors |
| Upgrade your account | Pricing |
9,000 transactional emails a month, free.
No credit card. No commitment. Knowing the limits means you’ll never hit them unexpectedly.