# Get outbound WhatsApp statistics by error code

`GET /v1/whatsapp/stats/error-codes`

Returns the count of failed WhatsApp messages grouped by normalized failure reason for the requested period. Rows are ranked by failure count descending and capped at the requested `limit` (default 50, max 200). Rows use send-time attribution, so a failure reported during the period for a message accepted earlier counts against the earlier period. A recent period therefore under-reports failures while reports are still arriving, and its counts grow as they land. The maximum window is 365 days; a longer range returns 422. A breakdown is already a single-dimension view and takes no dimension filter; to restrict statistics to a single template, category, phone number or tag, use the summary, daily or hourly statistics instead.

## Code samples

### TypeScript

```ts
const stats = await bird.whatsapp.stats.byErrorCode({ from: "2026-08-01", to: "2026-08-31" });
for (const row of stats.data ?? []) {
  console.log(row.error_code, row.count);
}
```

### Python

```py
stats = client.whatsapp.stats.by_error_code(from_="2026-08-01", to="2026-08-31")
for row in stats.data or []:
    print(row.error_code, row.count)
```

### Go

```go
stats, err := client.Whatsapp.Stats.ByErrorCode(context.Background(), bird.WhatsappStatsByErrorCodeParams{
	From: time.Now().AddDate(0, -1, 0),
	To:   time.Now(),
})
if err != nil {
	log.Fatal(err)
}
for _, row := range *stats.Data {
	fmt.Println(*row.ErrorCode, *row.Count)
}
```

### PHP

```php
$byErrorCode = $bird->whatsapp->stats->byErrorCode(['from' => '2026-08-01', 'to' => '2026-08-31']);
foreach ($byErrorCode->getData() ?? [] as $row) {
    echo $row->getErrorCode(), ' ', $row->getCount(), PHP_EOL;
}
```

### CLI

```sh
bird whatsapp stats by-error-code
```

### cURL

```sh
curl -X GET "https://us1.platform.bird.com/v1/whatsapp/stats/error-codes" \
  -H "Authorization: Bearer $TOKEN" \
  --url-query "limit=50"
```

## Example response `200`

```json
{
  "period": {
    "from": "2026-05-01",
    "to": "2026-05-25",
    "data_as_of": "2026-05-25T14:03:10Z"
  },
  "data": [
    {
      "error_code": "insufficient_balance",
      "count": 18
    }
  ],
  "total": 3
}
```

## 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 error-code rows to return, ranked by failure count 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.
- `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.
- `data` (array of object, required): Error-code rows ranked by failure count descending. Empty when no failures occurred in the period.
- `data.error_code` (string, required): The normalized failure reason this row aggregates, matching the `last_error.code` reported on an individual failed message.
- `data.count` (integer, required): Distinct messages that failed with this reason in scope.
- `total` (integer, required): Total distinct error codes with failures 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)
