Bytloop MailDocs
Status

Getting started

  • Introduction
  • Quickstart

Sending email

  • Send a transactional email
  • Sending domains vs mailboxes

Framework guides

  • Send email from Next.js
  • Send email from Ruby on Rails
  • Send email from Django
  • Send email from Laravel

Domains

  • Verify a domain

Receiving email

  • Receive email
  • Webhooks

Reference

  • Rate limits
  • Errors
  • SDKs

Reference

Rate limits

Per-plan send caps, per-key request limits, and how the 429 response looks.

Bytloop enforces two independent limits: a monthly send cap on the workspace (based on your plan) and a request-rate limit on every API key. Both surface a 429 Too Many Requests when tripped, with a Retry-After header telling you when to try again.

Monthly send cap#

The workspace-wide cap resets on the first day of each billing period. It counts every accepted send — bounced deliveries and suppressed recipients still count, since Bytloop still did the work to attempt them.

PlanEmails / monthSending domainsMailboxes
Free3,00013
Team50,0005Unlimited
ScaleCustomCustomUnlimited

Approaching the cap surfaces a banner in the dashboard and an email to workspace admins at 80% and 100%. Requests over the cap are rejected with 429, error code plan_cap_reached, until the next billing period or a plan upgrade.

Per-key request rate#

Each API key has an independent request-rate budget so a runaway script using one key cannot starve a well-behaved one. Defaults:

PlanRequests / second per keyBurst
Free1020
Team50100
ScaleNegotiatedNegotiated

The limiter is a token bucket, so short bursts up to the burst value are fine as long as the sustained rate stays under the per-second budget.

Batch endpoint#

Prefer POST /api/v1/emails/batch for high fan-out — up to 100 messages in a single request. Each message counts against the monthly cap, but the batch itself is a single request against the per-second budget.

429 response shape#

HTTP/1.1 429 Too Many Requests
Retry-After: 3
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Request rate exceeded for this API key. Retry after 3 seconds.",
    "retry_after_ms": 3000,
    "correlation_id": "cor_2N9pKqRxLvZ8yT"
  }
}
HTTP/1.1 429 Too Many Requests
Retry-After: 3
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Request rate exceeded for this API key. Retry after 3 seconds.",
    "retry_after_ms": 3000,
    "correlation_id": "cor_2N9pKqRxLvZ8yT"
  }
}

Back off, do not spin

A well-behaved client reads Retry-After (or retry_after_ms) and waits at least that long before retrying. Retrying immediately in a tight loop wastes budget and prolongs the outage.

Practical guidance#

  • Move slow work off the request path. Enqueue sends in your own worker instead of firing them synchronously from a user's request — a spike in traffic then queues up behind your worker's rate instead of flooding Bytloop.
  • Use idempotency keys on retries. Every 429 is safe to retry with the same Idempotency-Key; Bytloop will not double-send if the original request had already been accepted.
  • Split live and test traffic. Test keys have separate budgets, so a runaway CI job cannot starve your production send rate.

Next#

  • Handle the wider set of failure modes in Errors.
PreviousWebhooksNextErrors

On this page

  • Monthly send cap
  • Per-key request rate
  • Batch endpoint
  • 429 response shape
  • Practical guidance
  • Next