# Get outbound Apple Messages for Business statistics by message kind

`GET /v1/amb/stats/message-kinds`

Returns outbound counts and latency percentiles grouped by message content kind, for the requested period. Rows are ranked by accepted volume descending and capped at the requested `limit` (default 50, max 200). Rows use accepted-time attribution: a send failure recorded during the period for a message accepted earlier counts against the earlier period. Each row also carries `first_response` latency percentiles, omitted when no qualifying message contributes a measurement. There is no delivery receipt on this channel, so there is no `delivered` count anywhere in the row.
The maximum window is 365 days; a longer range returns `422`. Historical dates are supported within the maximum window length; the requested dates are not shifted forward. A breakdown is already a single-dimension view and takes no dimension filter; to restrict statistics to a single content kind, use the summary, daily, or hourly statistics instead.

## Code samples

**TypeScript**

```ts
const result = await bird.amb.stats.byMessageKind({ limit: 2 });
console.log(result);
```

Examples: [TypeScript](/docs/api/reference/get-amb-stats-by-message-kind.ts.md) · [Python](/docs/api/reference/get-amb-stats-by-message-kind.py.md) · [Go](/docs/api/reference/get-amb-stats-by-message-kind.go.md) · [PHP](/docs/api/reference/get-amb-stats-by-message-kind.php.md) · [CLI](/docs/api/reference/get-amb-stats-by-message-kind.cli.md) · [MCP](/docs/api/reference/get-amb-stats-by-message-kind.mcp.md) · [cURL](/docs/api/reference/get-amb-stats-by-message-kind.curl.md)

## Example response `200`

```json
{
  "period": {
    "from": "2026-05-01",
    "to": "2026-05-25",
    "data_as_of": "2026-05-25T14:03:10Z"
  },
  "attribution": "accepted_time",
  "data": [
    {
      "message_kind": "text",
      "counts": {
        "accepted": 4820,
        "sent": 4790,
        "send_failed": 30,
        "rejected": 4,
        "sent_rate": 0.9938,
        "send_failure_rate": 0.0062
      },
      "latency": {
        "processing": {
          "p50_ms": 610,
          "p95_ms": 2140,
          "p99_ms": 5380
        }
      },
      "first_response": {
        "p50_ms": 610,
        "p95_ms": 2140,
        "p99_ms": 5380
      }
    }
  ],
  "total": 4
}
```

## Query parameters

- `from` (string): Inclusive start of the window, a calendar day (YYYY-MM-DD). Interpreted in `timezone`, or UTC when omitted. Must not be after `to`. Max window 365 days. Defaults to 30 days before `to` when omitted.
- `to` (string): Inclusive end of the window, a calendar day (YYYY-MM-DD). Interpreted in `timezone`, or UTC when omitted. Max window 365 days. Defaults to today in that timezone when omitted.
- `timezone` (string): IANA timezone identifier used to group statistics, for example `Asia/Kathmandu`. The default is UTC. Day and hour boundaries, including the default window when `from` and `to` are omitted, follow this timezone. When this parameter is set, pass `from` and `to` as calendar days or `Z` instants instead of timestamps with explicit UTC offsets.
- `limit` (integer): Maximum number of content-kind rows to return, ranked by accepted volume descending.

## Response body

- `period` (object, required): The window the response covers (echoed back), plus `data_as_of`.
- `period.from` (string, required): Inclusive start of the window, as a calendar day (`YYYY-MM-DD`) or an RFC 3339 hour boundary. Historical starts are preserved; the maximum request length does not impose a historical cutoff.
- `period.to` (string, required): Inclusive end of the window, as a calendar day (`YYYY-MM-DD`) or an RFC 3339 hour boundary.
- `period.data_as_of` (nullable string): Latest time reflected in the statistics. More recent events might not be included yet. Null when the freshness boundary is unavailable.
- `attribution` (string, required)

  Always `accepted_time` for outbound statistics.

  Possible values: `accepted_time`, `event_time`
- `data` (array of object, required): Content-kind rows ranked by accepted volume descending.
- `data.message_kind` (string, required)

  The content kind these messages were sent as, the same value the message read returns as its content kind discriminator.

  Possible values: `text`, `attachment`, `rich_link`, `quick_reply`, `list_picker`, `time_picker`, `form`, `apple_pay`, `authenticate`, `imessage_app`, `interactive`
- `data.counts` (object, required): Outbound Apple Messages for Business counts for the requested scope, attributed to when each message was accepted. Apple Messages for Business has no delivery receipt, so there is no `delivered` count anywhere in this API: `sent` is the last outbound state Bird observes for a message. Very large counts are close estimates rather than exact tallies. Rates are computed once here, clamped to 1, and null when nothing was accepted.
- `data.counts.accepted` (integer, required): Distinct messages accepted for sending after admission checks. This is the denominator for `sent_rate` and `send_failure_rate`.
- `data.counts.sent` (integer, required): Distinct messages handed off to Apple.
- `data.counts.send_failed` (integer, required): Distinct accepted messages that Apple refused or that exhausted their send attempts. See `last_error.code` on the message for the reason; a refused charge is not a send failure, it is `rejected`.
- `data.counts.rejected` (integer, required): Distinct messages refused before any send attempt, because the destination has no price, the wallet could not fund the send, or the content cannot be sent yet. Rejected messages are never charged and are not counted in `accepted`, so the total addressed is `accepted + rejected`. Excluded from `send_failure_rate`, which covers send failures only.
- `data.counts.sent_rate` (nullable number, required): Share of accepted messages Apple acknowledged, computed as `sent / accepted`. Null when no messages were accepted in scope. This stands where other channels report a delivery rate.
- `data.counts.send_failure_rate` (nullable number, required): Share of accepted messages that failed to send, computed as `send_failed / accepted`. Null when no messages were accepted in scope.
- `data.latency` (object, required): Processing-latency percentiles in milliseconds for the requested scope, from acceptance to Apple handoff. Apple Messages for Business has no delivery receipt, so there is no `delivery` or `total` member beside `processing`. Conversation response timing is reported separately in `first_response`. Always present; every percentile is null when no qualifying message in scope has a measurement.
- `data.latency.processing` (object, required): Approximate p50, p95, and p99 latency percentiles in milliseconds for one latency family. All three are null when no qualifying event contributed a measurement.
- `data.latency.processing.p50_ms` (nullable integer, required): Median (50th percentile) latency in milliseconds. Null when no qualifying event contributed a measurement.
- `data.latency.processing.p95_ms` (nullable integer, required): 95th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.
- `data.latency.processing.p99_ms` (nullable integer, required): 99th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.
- `data.first_response` (object): First-response latency percentiles for this content kind. Omitted when no qualifying message contributes a measurement.
- `data.first_response.p50_ms` (nullable integer, required): Median (50th percentile) latency in milliseconds. Null when no qualifying event contributed a measurement.
- `data.first_response.p95_ms` (nullable integer, required): 95th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.
- `data.first_response.p99_ms` (nullable integer, required): 99th percentile latency in milliseconds. Null when no qualifying event contributed a measurement.
- `total` (integer, required): Total distinct content kinds with activity in the period, regardless of `limit`.

## Related resources

- [Should I use a Bird SDK or call the API directly?](/explained/platform/should-i-use-an-sdk-or-call-the-api-directly) (answer)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=api-basics)
