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 |
| Standard / Enterprise plan | — | — | See Pricing |
Preview accounts are created via the sign-up API for quick evaluation. Upgrade to a Standard or Enterprise plan to lift the per-minute and daily limits — a live key requires a paid plan.
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 upgrade to a Standard plan 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 15000 emails reached.",
"type": "rate_limit_error",
"upgrade_url": "https://brixus365.com/pricing",
"details": {
"limit": 15000,
"used": 15000
}
}
}
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 |
15,000 transactional emails a month on Standard.
No credit card. No commitment. Create an account, then upgrade to Standard for your first key.