---
title: "Get bounces by SMTP error code"
method: GET
path: "/v1/email/stats/bounce-codes"
tags: ["email-stats"]
---

# Get bounces by SMTP error code

`GET /v1/email/stats/bounce-codes`

## Request

- Base URL: `https://us1.platform.bird.com`
- URL: `https://us1.platform.bird.com/v1/email/stats/bounce-codes`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `bird_session`

Returns bounce counts for the requested period, grouped by the SMTP error code the receiving mail server returned. It answers the question of which SMTP responses are driving your bounces. Each row reports how many recipients bounced with that code, plus the hard, soft, admin, block, and undetermined split for that code.

This failure-only breakdown omits delivered, open, click, and rate fields because bounce codes occur only on bounce events.

Rows are ranked by the `sort` metric, `bounced` by default, and paginated with the requested `limit` (50 by default, 200 at most). They are computed against event time rather than send time. The window can span at most 365 days. Ask for more and you get a `422`.

## Query parameters

- `starting_after` string
- `ending_before` string
- `from` string, date
- `to` string, date
- `timezone` string
- `category` string
- `sort` 'bounced' | 'bounces.hard' | 'bounces.soft' | 'bounces.admin' | 'bounces.block' | 'bounces.undetermined'
- `limit` integer

## Headers

- `X-Workspace-Id` string
- `X-Organization-Id` string

## Response `200`

Per-SMTP-code bounce breakdown for the requested period.

- EmailStatsByBounceCodeResponse: Per-SMTP-code bounce breakdown for the requested period, ranked by the `sort` metric (default `bounced`) descending and paginated with the requested `limit` (default 50, max 200).
  - `period` EmailStatsPeriod, required: The date range this response was actually computed against. Echoed back so clients can render the period without tracking it themselves and so cached responses can be keyed by what was queried.
    - `from` string, date, required: Inclusive start date the response covers (YYYY-MM-DD).
    - `to` string, date, required: Inclusive end date the response covers (YYYY-MM-DD).
    - `data_as_of` string, date-time, nullable: The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response reflects data from up to a few seconds ago. Use this field to label data freshness (for example "as of 14:03") rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
  - `data` EmailBounceCodeStatsPoint[], required: Bounce-code breakdown rows, ranked by the `sort` metric (default `bounced`) descending. Empty when no bounces occurred in the period.
    - `smtp_error_code` string, required: The SMTP error code the receiving mail server returned for these bounces, as reported by that server (for example `5.1.1` for an unknown recipient, `4.2.2` for a full mailbox). The form varies by server, and the set of codes is open.
    - `bounced` integer, required: Distinct recipients whose delivery failed with this SMTP status code, approximately equal to the sum of the five `bounces.*` sub-counts. The two are computed independently, so they can differ slightly because of approximation.
    - `bounces` EmailBounceStats, required: Breakdown of `bounced` by failure type. Each field counts distinct bounced recipients of that type in this row's scope; the five types approximately partition `bounced`.
      - `hard` integer, required: Distinct recipients with a permanent delivery failure (invalid address or non-existent domain). The address is automatically added to the suppression list.
      - `soft` integer, required: Distinct recipients with a transient delivery failure (mailbox full or server temporarily unavailable). Delivery was retried.
      - `admin` integer, required: Distinct recipients refused by a policy at the receiving end, such as relaying denied or a blocklisted domain. Fix these by changing your content or sender configuration. Cleaning the recipient list does not usually help.
      - `block` integer, required: Distinct recipients bounced because the receiving mail server blocked the sending IP for reputation reasons (mail block, spam block, spam content). Triage usually focuses on IP reputation and sending volume.
      - `undetermined` integer, required: Distinct recipients bounced where the receiving server's response did not allow precise classification.
  - `total` integer, required: Total number of distinct SMTP error codes with activity in the period, regardless of `limit`. Pass `next_cursor` as `starting_after` to request the next page.
  - `next_cursor` string, nullable, required: Cursor for the next page. Pass back as `starting_after` to advance forward. `null` when no next page exists.
  - `prev_cursor` string, nullable, required: Cursor for the previous page. Pass back as `ending_before` to step backward. `null` when no previous page exists.
  - `refresh_cursor` string, nullable, required: Refresh anchor, the first row of this response. Pass back as `ending_before` to fetch what precedes it in the current sort order. On a newest-first sort those are the items that have appeared since; on any other sort they are the items that sort earlier, so refreshing such a list means re-fetching it instead. Non-`null` whenever `data` is non-empty; `null` only on an empty page. Distinct from `prev_cursor`.

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Insufficient permissions
- `404`: Resource not found
- `422`: The request has invalid field values, violates a business rule, or carries a query parameter the endpoint does not declare. Field validation errors use `type: validation_error` and include the affected fields in `details`. Business-rule errors identify the failed rule in `type`.
- `429`: Rate limit exceeded
- `500`: Internal server error
- `503`: The service is temporarily unavailable. If `Retry-After` is present, wait for that delay before retrying; otherwise, retry with exponential backoff. Reuse the same idempotency key and request when retrying a mutation.

---

[API](https://skmtc.dev/messagebird/apis/bird-api.md) · [All operations](https://skmtc.dev/messagebird/apis/bird-api/llms.txt) · [OpenAPI document](https://skmtc.dev/messagebird/apis/bird-api/revisions/3e2a50466454?raw)
