> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dial Metrics

> Read your dials-per-second (DPS) history and live rate with GET /v2/dial_metrics, and compare peak DPS with your limit.

## Overview

<Note>`GET /v2/dial_metrics` is in **development** and can change before general availability.</Note>

[`GET /v2/dial_metrics`](/api-reference/call-information/list-dial-metrics) returns the outbound dial rate your account produced through the Voice API `Dial` command and TeXML, next to the [dials-per-second limit](/docs/voice/programmable-voice/dials-per-second-limit) in force at the time. Use it to chart dial volume, see when the limit rejected dials, and size a limit increase request.

Each `dial_metric` record is one bucket: one region, one time interval. Results are newest first by default; see [Sort order](#sort-order).

```json theme={null}
{
  "record_type": "dial_metric",
  "region": "us",
  "start_time": "2026-09-29T12:00:00.000Z",
  "end_time": "2026-09-29T13:00:00.000Z",
  "dials": {
    "total": 85600,
    "accepted": 85240,
    "rejected": { "dps_limit": 360, "hourly_limit": 0, "daily_limit": 0 }
  },
  "average_dps": 23.7778,
  "peak_dps": 104.0,
  "dps_limit": 100
}
```

## Choose a granularity

`granularity` is required. It sets the bucket size and the history available.

| `granularity` | Bucket size | History available | Use for |
| - | - | - | - |
| `second` | 5 seconds | Last 48 hours | Live rate, short-range charts |
| `minute` | 1 minute | Last 30 days | Daily charts |
| `hour` | 1 hour | Last 30 days | Capacity planning, peak comparison |

A request whose `start_time` is older than the retention window of its granularity fails with `422` and error code `10033`. The response does not return empty data.

`start_time` is inclusive and `end_time` is exclusive. A bucket is returned when it **starts** inside that range. Both are ISO 8601 date-times, for example `2026-09-29T12:00:00.000Z`.

## Read the live rate

There is no separate "current" endpoint. The live rate is the newest `granularity=second` record of each region. Request the last two minutes newest first:

```bash theme={null}
curl -G "https://api.telnyx.com/v2/dial_metrics" \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  --data-urlencode "granularity=second" \
  --data-urlencode "sort=-start_time" \
  --data-urlencode "start_time=$(date -u -v-2M +%Y-%m-%dT%H:%M:%SZ)" \
  --data-urlencode "end_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
```

The `date -v-2M` form is macOS. On Linux use `date -u -d '2 minutes ago' +%Y-%m-%dT%H:%M:%SZ`. Records come newest first, so the first record for each `region` is that region's live rate. Do not use `page[limit]=1`: it returns a single record, and with traffic in more than one region it hides the others. A region with no record in the window has a live rate of 0.

Telnyx counts a 5-second window only after every call-processing node has reported it, about 15 seconds after the window closes. The newest record is therefore about 20 seconds old. The same rule applies to every granularity: an in-progress minute or hour contains complete 5-second windows only.

## Sort order

`sort` takes `-start_time` (default, newest first) or `start_time` (oldest first). `region` follows the same direction for records with the same `start_time`. Any other value returns `422` with error code `10032` and `source.parameter` set to `sort`. The response echoes the applied value in `meta.sort`.

## Missing buckets are zero

The API returns only buckets in which at least one dial occurred. Treat a missing bucket as zero dials and 0 DPS. If no `second` record exists for the last minute or so, the live rate is 0.

## Compare peak DPS with the limit

For each bucket:

* `dials.total`, `average_dps`, and `peak_dps` count every dial attempt, rejected ones included.
* `average_dps` is `dials.total` divided by the bucket duration, rounded to 4 decimal places.
* `peak_dps` is the busiest 5-second window in the bucket, rounded to 4 decimal places, with all call-processing nodes of the region added together first. For `granularity=second` it equals `average_dps`.
* `dps_limit` is the limit in force during that busiest window. `null` means unlimited.

Because `peak_dps` and `dps_limit` describe the same window, compare them directly. `peak_dps` above `dps_limit` is expected when dials were rejected. `dials.rejected.dps_limit` is the authoritative signal: if it is above 0, dials in that bucket were rejected by the DPS limit. Do not compare `average_dps` with `dps_limit`: bursts hide inside the average.

Dials rejected by a limit are still counted in `dials.total`. `dials.rejected` splits them by `dps_limit`, `hourly_limit`, and `daily_limit`.

### How the limit is enforced

Telnyx enforces your DPS limit per region over fixed 5-second windows: a window allows `dps_limit × 5` dial attempts. Several call-processing nodes share each region's limit, and they exchange their counts with a short delay. Near the limit, a few dials can therefore be rejected while a window's total is just under `dps_limit × 5`, or accepted while it is just over. The counts this API returns are exact; only enforcement at the threshold is approximate. To avoid rejections, pace dials with headroom below your limit instead of at it. See [Dials Per Second Limit](/docs/voice/programmable-voice/dials-per-second-limit) for the default limit and how to raise it.

## Regions are not summed

`region` is a string. Current values are `us`, `eu`, `australia`, `middle_east`, `canada`, and `india`. Telnyx can add values, so your client must tolerate regions it does not recognize.

The DPS limit is enforced per region, so the API returns one record per region per bucket, ordered by `start_time` and then `region`. Do not add records of different regions together: the sum can exceed every limit without any dial being rejected, and no limit applies to it. Group by `region` and compare each series with its own `dps_limit`.

## Paginate

Results are cursor paginated. `page[limit]` defaults to 1,000 and is clamped to 1-10,000. The response carries no total count.

When more records follow, `meta.next` holds the path of the next page and `meta.cursors.after` holds its cursor. On the last page `meta.cursors` is empty and `meta.next` is absent. Treat cursors as opaque.

If `page[after]` matches no records, the response is an empty page, not an error. `meta.cursors.after` and `meta.cursors.before` both echo the cursor you sent.

```bash theme={null}
#!/usr/bin/env bash
# Print every hourly bucket for a range, newest first (the default order),
# following meta.next until it is absent. meta.next keeps the sort order.
# Add &sort=start_time to the first URL to read oldest first.
BASE="https://api.telnyx.com"
path="/v2/dial_metrics?granularity=hour&start_time=2026-09-29T00:00:00Z&end_time=2026-09-30T00:00:00Z&page[limit]=500"

while [ -n "$path" ] && [ "$path" != "null" ]; do
  body=$(curl -sg "$BASE$path" -H "Authorization: Bearer $TELNYX_API_KEY")
  echo "$body" | jq -c '.data[]'
  path=$(echo "$body" | jq -r '.meta.next // empty')
done
```

Use the same loop in any HTTP client: request the URL, process `data`, and request `meta.next` until it is absent.

## Errors

Errors use the standard `errors` array, with `source.parameter` naming the field at fault.

* `401`, code `10009`: authentication failed.
* `422`, code `10004`: `granularity`, `start_time`, or `end_time` is missing.
* `422`, code `10032`: `granularity` is not `second`, `minute`, or `hour`, or `sort` is not `-start_time` or `start_time`.
* `422`, code `10026`: a date-time, `page[limit]`, or `page[after]` is invalid.
* `422`, code `10033`: `end_time` is not after `start_time`, or `start_time` is outside the retention window.
* `404`, code `10005`: the route does not exist.
* `429`: the API request rate limit was exceeded. Responses carry the `X-RateLimit-*` headers and, when supplied, `Retry-After`. See [API rate limiting](/docs/development/api-fundamentals/reliability/rate-limiting).
* `500`, code `10007`: unexpected error.

## Rate limits

Requests to this endpoint are rate limited per user. Above the limit the API returns `429` with error code `10011`; every response carries the `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers, so read them instead of hard-coding a limit. New data arrives every 5 seconds, so polling the live rate more often than that returns nothing new. See [API rate limiting](/docs/development/api-fundamentals/reliability/rate-limiting) for how to back off.

## Related

* [Dials Per Second Limit](/docs/voice/programmable-voice/dials-per-second-limit) — default limit, how it is calculated, and how to raise it.
* [API errors](/docs/development/api-fundamentals/api-errors) — general error format and codes.
