# Tiers, quotas, and sandbox limits

Every account sends against a **daily send cap** plus a few per-tier resource
limits (mailboxes, custom domains, webhook endpoints, retained storage). New
accounts on the trial states (sandbox and pay-as-you-go) also ramp up gradually
as they build a clean sending history. This page is the single source for those
numbers and for the quota-preflight and rate-limit contracts you read back from
the API.

## At a glance

| Limit | Sandbox | Pay-as-you-go | Starter | Pro |
|---|---|---|---|---|
| Daily send cap | 15/day | 200/day (reputation cap; billed per send) | 233/day | 1,000/day |
| Mailboxes | 1 | 1 | 5 | 25 |
| Custom domains | 1 | 1 | 1 | 3 |
| Webhook endpoints | 1 | 3 | 3 | 25 |
| Retained storage | 1 GB | 5 GB | 5 GB | 15 GB |

The daily send cap above is the tier **ceiling**. The value actually enforced on
any given day is the *effective* cap, which the trial-state ramp (below) can hold
lower until your account is established. Always read your live effective cap from
`GET /v1/accounts/quota` rather than assuming the ceiling.

For sending volume beyond Pro, get in touch with the team.

## Daily send cap and the new-sender ramp

- **Trial states (sandbox, pay-as-you-go)** start at **15 sends/day** and lift
  to **200/day** once you have a clean send history. Sandbox's ceiling is
  15/day, so a sandbox account stays at 15. Pay-as-you-go's ceiling is also
  200/day — each send is still billed individually, but the daily cap is a
  reputation limit set deliberately below Starter's 233/day, so it stops
  rising once the ramp reaches it.
- **Subscription [tiers](/pricing) (Starter, Pro)** are coupled to their **full ceiling
  immediately on your first cleared charge**, regardless of the ramp. Starter =
  233/day, Pro = 1,000/day.

The cap is a rolling per-UTC-day counter. It resets at midnight UTC.

## Checking your quota

`GET /v1/accounts/quota` is an agent-safe preflight: it works with mailbox-scoped
agent keys as well as admin keys and returns only send-budget fields (no
account-wide detail). Call it before a batch of sends to see how much headroom is
left today.

```http
GET /v1/accounts/quota
Authorization: Bearer rly_live_<id>.<secret>
```

```json
{
  "today": { "count": 12, "limit": 233, "day": "2026-07-02" },
  "sends_remaining": 221,
  "reset_at": "2026-07-03T00:00:00.000Z",
  "scope": "agent",
  "bound_mailbox_ids": ["<mailbox-uuid>"]
}
```

| Field | Meaning |
|---|---|
| `today.count` | Sends already charged against today's budget (UTC). |
| `today.limit` | Your **effective** daily cap — the number the send gate enforces today. |
| `today.day` | The UTC budget day, `YYYY-MM-DD`. |
| `sends_remaining` | `max(0, today.limit − today.count)`. Never negative. |
| `reset_at` | ISO-8601 UTC timestamp of the next midnight, when the budget resets. |
| `scope` | `agent` for a mailbox-scoped key, `admin` for an unrestricted key. |
| `bound_mailbox_ids` | The mailboxes an agent key is bound to (empty for an admin key). |

### Warm-up disclosure (present only when active)

When a new-sender warm-up applies to your account, the quota response carries an
extra `warmup` object. Treat it as optional — branch on its presence, and when
it is absent your full effective cap applies.

```json
{
  "warmup": {
    "until": "2026-07-05T00:00:00.000Z",
    "shared_domain_daily_limit": 334,
    "velocity_gate_mode": "log_only",
    "reason": "New-sender warm-up protects your sending reputation on the shared pool. Verify your own domain for instant full volume."
  }
}
```

| Field | Meaning |
|---|---|
| `until` | ISO-8601 UTC timestamp when the warm-up window ends. |
| `shared_domain_daily_limit` | The reduced daily cap while warming up on the shared pool. |
| `velocity_gate_mode` | `log_only` or `enforced`. |
| `reason` | Human-readable explanation, including the escape hatch. |

Verifying your own custom domain moves your sending to an isolated domain, which
lifts the shared-pool warm-up.

## When you hit the cap

Once today's budget is exhausted, send and reply calls return **`429`** with the
code **`RATE_LIMITED`** and a `details` object you can use to schedule a retry:

```http
HTTP/1.1 429 Too Many Requests

{
  "error": "Daily send limit reached",
  "code": "RATE_LIMITED",
  "details": {
    "daily_limit": 233,
    "sends_remaining": 0,
    "reset_at": "2026-07-03T00:00:00.000Z"
  }
}
```

`sends_remaining` is always `0` on this error (that is precisely why it fired),
and `reset_at` tells you when the budget rolls over. Wait until `reset_at` rather
than retrying immediately — a retry before the reset returns the same `429`.

A `RATE_LIMITED` `429` may instead carry `details.reason: "new_account_warmup"`
with a `retry_after_seconds` value when a new-sender warm-up throttle is in
effect. Back off for that many seconds in that case.

`RATE_LIMITED` is only one of the send-gate outcomes. For everything else that
can block a send (suppression, recipient containment, strict-recipient, MX
validation, sandbox gates), see the [send-gate decision tree](/agents/send-gates);
for the full error-code catalog, see the [error reference](/agents/errors).

## Sandbox restrictions

Sandbox is the default trial state on signup. On top of the 15/day cap it adds:

- **A temporary trial address.** Your sandbox mailbox's address lives on
  ReplyLayer's shared trial domain and is temporary to the trial — it isn't
  meant for production use. When you upgrade to a paid tier, you get your own
  dedicated platform subdomain (or bring your own domain) and choose the
  production identity your agent sends from going forward. At upgrade the
  trial mailbox is **retired** (paused): its threads and messages stay
  readable and exportable, but it stops sending and stops receiving new
  inbound — the retirement is immediate, not a grace window.
- **A cumulative trial budget of 250 total sends** across the whole trial (not
  per day). When it is exhausted, sends return **`403 SANDBOX_TRIAL_BUDGET_EXHAUSTED`**.
  Adding pay-as-you-go credits or upgrading to Starter clears it.
- **A 30-day trial clock.**
- **One mailbox.**
- **A verified-recipient ramp.** You can add up to **5** confirmed recipients in
  your first **72 hours**, rising to **25** after that window. Recipients must be
  confirmed before you can send to them; exceeding the cap returns `403 TIER_LIMIT`
  with a `ramp_until` timestamp.
- **A footer watermark** appended to outbound messages. Sending from your own
  verified custom domain suppresses it.

### The simulator exemption

Sends to `simulator.replylayer.net` addresses (`delivered@`, `bounced@`, `complained@`,
`suppressed@`) — ReplyLayer's own first-party simulator — are exempt from the sandbox
verified-recipient confirmation requirement (and are never auto-suppressed), so your
onboarding test send in the [quickstart](/docs/quickstart) works immediately without
pre-confirming a recipient. The exact four scenario addresses and their `+label` forms
also bypass the recipient-domain concentration cap below, so one Sandbox account can
run all four in the same 24-hour period. Simulator sends still consume daily and
cumulative Sandbox allowances, remain in the send-attempt ledger, and are subject to
authentication, API rate limits, scanning and review policy, and idempotency. The
exemption does not apply to another local part, subdomain, or lookalike domain. The
[email simulator guide](/docs/guides/simulator) defines each scenario and its
billing, suppression, and reputation behavior.

## Attachment capabilities by tier

Receiving attachments, their metadata, and viewing previews in the dashboard are
available on every tier. The paid gates are:

| Capability | Sandbox | Pay-as-you-go | Starter | Pro |
|---|---|---|---|---|
| Receive attachments + metadata | ✓ | ✓ | ✓ | ✓ |
| Dashboard attachment preview | ✓ | ✓ | ✓ | ✓ |
| Agent-key preview API (derived text) | — | ✓ | ✓ | ✓ |
| Approved raw attachment download | — | — | — | ✓ |
| Outbound attachment sending | — | — | — | ✓ |

A bound agent key on a tier without the agent-preview gate receives
`403 ATTACHMENT_PREVIEW_DISABLED` from the preview route. For the full staging →
poll → `attachment_ids` → consume-once lifecycle and its failure codes, see
[attachments for agents](/agents/attachments).

## Related

- [Quickstart](/docs/quickstart) — your first send.
- [Send-gate decision tree](/agents/send-gates) — why a send was blocked.
- [Error reference](/agents/errors) — the full code catalog.
- [Attachments](/agents/attachments) — staging lifecycle and limits.
