Home /Docs /Transactional Email Counting

How Transactional Emails Are Counted

Transactional emails are the messages you send through the Email API. This page explains exactly what counts toward your plan, what does not, and how the billing window is calculated.

Overview

Every email you send with POST /api/v1/emails is a transactional email. Usage is metered per recipient — not per API request — and only the recipients inside your to list are counted. Usage is always measured against the current billing window, which rolls monthly from the day your API subscription started.

In short: count = number of addresses in the to array of each non-reply send in the current cycle.

The counting unit: recipients

A single API call can address up to 1,000 recipients in its to list. Each address in that list is counted as one transactional email. So one request to 50 recipients consumes 50 from your plan — not 1.

Internally, the count is the cardinality (length) of the stored recipients array:

-- per send, the contribution to usage is:
cardinality(recipients)   -- = number of "to" addresses

What counts

  • Each address in the to list of a successful POST /api/v1/emails send.
  • The send is counted at enqueue time (when the email row is persisted), not at delivery time. A recipient still counts even if the message later bounces.
  • Hard bounces are counted again, separately, to compute your bounce rate — they do not reduce your usage total.

What does not count

  • cc and bcc recipients. Only the to array is metered.
  • Replies. Messages sent via the reply endpoints (/reply) are flagged is_reply = true and are excluded from usage.
  • Deleted rows. Sends that have been soft-deleted (deleted_at IS NOT NULL) are excluded.
  • Sends outside the current cycle. Only the active billing window is counted toward your quota.

The exact query

Usage for the current cycle is a single scan that returns both the sent count and the hard-bounced count:

SELECT
  COALESCE(SUM(cardinality(recipients)), 0) AS sent,
  COALESCE(SUM(
    CASE WHEN is_bounced = true
         THEN cardinality(recipients)
         ELSE 0
    END
  ), 0) AS hard_bounced
FROM email_apis
WHERE organization_id = :orgId
  AND created_at >= :cycleStart   -- inclusive
  AND created_at <  :cycleEnd     -- exclusive
  AND deleted_at IS NULL
  AND is_reply = false;

The billing window

Usage is not measured against the calendar month. It is measured against a rolling monthly cycle anchored to the day your API subscription started (started_at). The current cycle is the half-open interval [cycleStart, cycleEnd) — start inclusive, end exclusive — and the count resets to 0 at the start of each new cycle.

  • The first cycle begins on the subscription anchor date.
  • Each cycle advances one month at a time until the next boundary would fall after today.
  • All boundaries are evaluated in UTC at start-of-day.

Example

anchor (started_at) = 2025-11-11

today = 2025-11-29   ->  cycle = [2025-11-11, 2025-12-11)
today = 2025-12-20   ->  cycle = [2025-12-11, 2026-01-11)
today = 2026-01-11   ->  cycle = [2026-01-11, 2026-02-11)   // resets

Note: if your organization has no active API subscription, usage is reported as 0 and the plan cap is shown as-is.

Quota & remaining

Your plan defines a monthly send cap (sends_cap). Remaining capacity is simply:

remaining = monthlyCap - sentInCurrentCycle

The remaining value can go negative if a single batch send pushes you past the cap; the cap is checked per request rather than per recipient, so a large to list can overshoot.

Bounce rate & account state

Alongside the sent count, SendTrim tracks how many of those recipients hard-bounced in the same cycle and derives a bounce rate:

bounceRate = hardBouncedInCycle / sentInCycle

That rate drives an account state used to protect deliverability:

GOOD

Bounce rate ≤ 2%. Normal sending.

WARNING

Bounce rate > 2%. Sending continues; clean your lists.

SUSPENDED

Bounce rate > 5% (after ≥ 100 sends). New API sends are rejected with 400.

Below 100 sends in a cycle, the account can only be GOOD or WARNING — suspension only applies once there is a statistically meaningful volume (≥ 100 sends).

Worked examples

1 request, 3 recipients

to:  ["a@x.com", "b@x.com", "c@x.com"]
cc:  ["mgr@x.com"]
bcc: ["audit@x.com"]

counted = 3   // only "to"; cc and bcc are ignored

A reply does not count

POST /api/v1/emails/{referenceId}/reply
to: ["customer@x.com"]

counted = 0   // is_reply = true -> excluded from usage

Cycle total

Cycle [2025-11-11, 2025-12-11):
  send #1  to: 200 recipients   -> +200
  send #2  to: 50 recipients    -> +50
  reply    to: 1 recipient      -> +0
  send #3  to: 300 (later deleted) -> +0 (deleted_at set)

sentInCycle = 250

FAQ

Does sending to the same address twice count twice?

Yes. Counting is per recipient per send, with no deduplication across requests.

Do bounced emails refund my usage?

No. A recipient is counted when the send is enqueued. Bounces are tracked separately only to compute your bounce rate.

When does my counter reset?

At the start of each monthly cycle, anchored to your subscription start date — not on the 1st of the calendar month.

Where can I see my current usage?

The API usage summary returns sent, remaining, hardBounces, bounceRate, and state for the current cycle.