Skip to main content

Rate Limits & Retention

Two independent limits apply to your account, each with its own headers and its own 429 behavior:

  1. API request rate limits — how many API calls (of any kind) you can make per minute/hour, keyed to your credential.
  2. Send volume quotas — how many emails POST /v1/send will accept, keyed to your Motor Block and your account plan.

Do not confuse the two: a 429 from one has no bearing on the other, and they use different response headers (X-RateLimit-* vs RateLimit-*, below).

API Request Rate Limits

Every authenticated request — Public Analytics API and HTTP Send API alike — is capped per credential (per Motor Block API key, per Account API key, or per Public API bearer token). Responses include:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 98
X-RateLimit-Reset: 23
HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetSeconds until the rate limit window resets

Some unauthenticated utility endpoints and early validation failures may not include these headers. Treat them as rate-limit metadata for authenticated API calls, not as a replacement for handling 429 Too Many Requests.

On the rare path where the request limiter itself is unavailable, X-RateLimit-Remaining is the literal string unknown rather than a number — parse defensively.

Best practices:

  1. Check X-RateLimit-Remaining before making requests
  2. Implement exponential backoff on 429 responses
  3. Add delays between batch requests: sleep 1 in bash, time.sleep(1) in Python
  4. Cache responses where possible to reduce API calls

Send Volume Quotas

Separately from the API request limiter above, POST /v1/send (and, on the SMTP side, mail submitted directly to mail.motorical.com) is capped against two send-volume ceilings that share the same burst/hourly/daily counters shown on your dashboard's Usage page:

CeilingScopeWhere to check it
Motor Block limitBurst, hourly, and daily caps on one Motor Block — either your configured limits, or a lower reputation-based throttle if one is active, whichever is lowerGET /motor-blocks/{id}/rate-limits
Account-wide limitCombined hourly and daily caps across every Motor Block on your account, derived from your subscription planGET /account/rate-limits

Both ceilings are evaluated on every POST /v1/send call and increment the same shared counters used by SMTP submission — sending through one path counts against the other. dryRun: true requests are validated but never charged against either ceiling.

:::note Account-wide enforcement is rolling out gradually The Motor Block limit is enforced today: exceeding it returns 429 with error: "rate_limited_block". The account-wide limit is currently monitored, not yet enforcedGET /account/rate-limits already reports real usage against it so you can watch your standing ahead of time, but POST /v1/send will not refuse a message for exceeding it until account-wide enforcement is fully rolled out. Don't build logic that assumes today's behavior is permanent — build to handle rate_limited_account (below) now, ahead of enforcement. :::

Response headers on /v1/send

A send that is accepted, and a send refused for a Motor Block or account ceiling, carry:

RateLimit-Limit: 10000
RateLimit-Remaining: 9999
RateLimit-Reset: 33953

These are distinct from X-RateLimit-* above (no X- prefix): they describe a send ceiling, not your API request budget. On an accepted send they report the Motor Block's daily ceiling. On a 429 they report whichever dimension actually bound — burst, hourly, daily, or (once account enforcement is on) the account-wide ceiling — with RateLimit-Remaining: 0 and a Retry-After header in seconds.

They are not present on:

  • dryRun: true responses — the request never reaches the quota check
  • validation, disallowed-header, auth, domain, DNS, or sandbox failures (422, 400, 401, 403, 404), all refused before the quota check
  • the rate_limited_warmup refusal, which sets only Retry-After
  • any response where the quota check itself was unavailable — Motorical fails open and accepts the message rather than emitting placeholder numbers

Missing headers mean "unknown", never "unlimited". Poll GET /account/rate-limits when you need a reliable figure.

429 error slugs on /v1/send

{
"success": false,
"error": "rate_limited_block",
"message": "Rate limit exceeded (daily)",
"retryAfterSeconds": 33953
}
error slugMeaningEnforced today?
rate_limited_blockThe Motor Block's burst, hourly, or daily cap was exceededYes
rate_limited_accountThe account-wide hourly or daily cap was exceededNot yet — rolling out (see above)
rate_limited_warmupThe sending domain is still warming up and its send buffer is fullNot yet — rolling out

All three use the same Retry-After / retryAfterSeconds contract. Treat any of them the same way you'd treat 429 from the API request limiter: back off and retry after the indicated window, don't hammer.

SMTP submission

SMTP submission on mail.motorical.com:2587 / :2465 shares these exact counters — a message sent over SMTP decrements the same burst/hourly/daily and account buckets as one sent over POST /v1/send. Over-quota SMTP submissions are refused with a temporary 451 4.7.1 reply naming the bound ceiling. See SMTP troubleshooting → Rate Limiting for the exact reply strings.

Handling Rate Limits

When you exceed either the API request limit or a send volume quota, you'll receive a 429 Too Many Requests response — check the response body's error field (above) to tell which one it was.

Best practices:

  1. Check X-RateLimit-Remaining (API requests) and GET /account/rate-limits (send volume) before making requests
  2. Implement exponential backoff on 429 responses
  3. Add delays between batch requests: sleep 1 in bash, time.sleep(1) in Python
  4. Cache responses where possible to reduce API calls

Data Retention

Requests for data outside your plan's retention window are rejected with a 400 Bad Request response. Check your plan's retention limits in the dashboard under Settings → Usage.

Time Parameters

All time parameters use ISO 8601 format:

2024-01-15T14:30:00Z

Timestamps must fall within your plan's retention window.