# APM API

> Read where request time goes, which endpoints and operations consume it, what regressed after a deploy, slow examples, dependencies and distributed traces.

Source: https://www.apitraffic.io/docs/api-reference/apm

These operations answer the questions on the app's [APM](https://www.apitraffic.io/docs/apm/overview) pages: where request time goes, which endpoints use the most of it, what got slower, and which requests belong to one distributed trace. The first four are computed from the per-request APM totals, so they stay fast at any traffic volume. The [APM analytics](#apm-analytics) operations go deeper: span operations and endpoints ranked on the server, trends, heatmaps, before-and-after comparisons, slow examples and dependencies. For individual operations, see also the [Spans API](https://www.apitraffic.io/docs/api-reference/spans).

**Plan:** needs a plan that includes **APM**; otherwise every operation answers `403` with code `2221`. **Permissions:** any member, or a `user` or `administrator` API token.

All times are ISO 8601 in UTC, for example `2026-10-19T00:00:00.000Z`. Durations are in milliseconds.

## Time breakdown

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/breakdown`

Splits request time into database, cache, outbound HTTP, queue and RPC, and application time, as a total for the range and as a time series. Application time is what remains after the instrumented operations, never below 0.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range.

- **environmentSid (query, string)**:
  Only this environment.

- **bucketSid (query, string)**:
  Only this bucket.

- **endpoint (query, string)**:
  Only this endpoint, for example `/v1/orders/{order_id}`.

### Response

- **summary (object, required)**:
  The whole range.

**summary**

- **requestCount (number)**: Requests.

- **errorCount (number)**: Requests that failed.

- **totalMs (number)**: Wall-clock time of the requests.

- **dbMs (number)**: Time in database queries.

- **cacheMs (number)**: Time in Redis and other caches.

- **httpOutMs (number)**: Time in outbound HTTP calls.

- **queueMs (number)**: Time in queue and RPC calls.

- **appMs (number)**: Remaining in-process time.

- **spanCount (number)**: Spans recorded.

- **p50Ms (number)**: Median request duration.

- **p95Ms (number)**: 95th percentile duration.

- **p99Ms (number)**: 99th percentile duration.

- **timeseries (object[], required)**:
  The same fields per period (without `p50Ms` and `p99Ms`), plus `bucket`: the start of the period. The period width follows the length of the range.

- **rollup (boolean, required)**:
  `true` when the answer came from pre-aggregated metrics.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/breakdown \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'startTime=2026-10-19T00:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T00:00:00.000Z' \
  --data-urlencode 'bucketSid=k3m9p2x'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  startTime: '2026-10-19T00:00:00.000Z',
  endTime: '2026-10-20T00:00:00.000Z',
  bucketSid: 'k3m9p2x',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/breakdown?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { summary } = await response.json();
console.log(`database share: ${Math.round((summary.dbMs / summary.totalMs) * 100)}%`);
```

```json 200
{
  "summary": {
    "requestCount": 10412,
    "errorCount": 538,
    "totalMs": 1484700,
    "dbMs": 612300,
    "cacheMs": 21400,
    "httpOutMs": 498100,
    "queueMs": 0,
    "appMs": 352900,
    "spanCount": 88210,
    "p50Ms": 61,
    "p95Ms": 410,
    "p99Ms": 1240
  },
  "timeseries": [
    {
      "bucket": "2026-10-19T14:00:00.000Z",
      "requestCount": 702,
      "errorCount": 61,
      "totalMs": 272400,
      "dbMs": 41800,
      "cacheMs": 1500,
      "httpOutMs": 201300,
      "queueMs": 0,
      "appMs": 27800,
      "spanCount": 5960,
      "p95Ms": 3980
    }
  ],
  "rollup": true
}
```

## Endpoints by time consumed

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/endpoints`

Ranks endpoints by the total time they consume, with the same split as [Time breakdown](#time-breakdown). Total time, not average latency, shows where your capacity goes: a fast endpoint called constantly can cost more than a slow one called rarely.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range.

- **environmentSid (query, string)**:
  Only this environment.

- **bucketSid (query, string)**:
  Only this bucket.

- **limit (query, integer, default 50)**:
  Endpoints to return, 1 to 1000.

### Response

- **points (object[], required)**:
  One entry per endpoint, most time first: `endpoint`, `requestCount`, `errorCount`, `averageDurationMs`, `p95Ms`, `p99Ms`, `lastSeen`, and the time split `totalMs`, `dbMs`, `cacheMs`, `httpOutMs`, `queueMs`, `appMs` and `spanCount`.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/endpoints \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'startTime=2026-10-19T00:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T00:00:00.000Z' \
  --data-urlencode 'limit=10'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  startTime: '2026-10-19T00:00:00.000Z',
  endTime: '2026-10-20T00:00:00.000Z',
  limit: '10',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/endpoints?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "points": [
    {
      "endpoint": "/v1/checkout",
      "requestCount": 612,
      "errorCount": 9,
      "averageDurationMs": 684,
      "p95Ms": 1420,
      "p99Ms": 2310,
      "lastSeen": "2026-10-19T23:58:41.000Z",
      "totalMs": 418600,
      "dbMs": 96300,
      "cacheMs": 2100,
      "httpOutMs": 287400,
      "queueMs": 0,
      "appMs": 32800,
      "spanCount": 9180
    },
    {
      "endpoint": "/v1/orders/{order_id}",
      "requestCount": 1830,
      "errorCount": 22,
      "averageDurationMs": 171,
      "p95Ms": 512,
      "p99Ms": 940,
      "lastSeen": "2026-10-19T23:59:12.000Z",
      "totalMs": 312900,
      "dbMs": 261700,
      "cacheMs": 4100,
      "httpOutMs": 0,
      "queueMs": 0,
      "appMs": 47100,
      "spanCount": 42090
    }
  ]
}
```

## Regressions

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/regressions`

Finds endpoints whose latency or error rate moved against a baseline window, ranked by how much the change matters given their traffic.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Query parameters

- **startTime (query, string, required)**:
  Start of the window to examine.

- **endTime (query, string, required)**:
  End of the window to examine.

- **environmentSid (query, string)**:
  Only this environment.

- **bucketSid (query, string)**:
  Only this bucket.

- **baseline (query, string, default previous)**:
  `previous` compares with the window just before, of the same length. `weekAgo` compares with the same window seven days earlier, which suits traffic with a weekly shape.

- **minRequests (query, integer, default 20)**:
  Ignore endpoints with fewer requests than this in either window, 1 to 1,000,000.

- **limit (query, integer, default 20)**:
  Endpoints to return, 1 to 1000.

### Response

- **baseline (string, required)**:
  The baseline used.

- **points (object[], required)**:
  One entry per endpoint, most significant first.

**point**

- **endpoint (string)**: The endpoint.

- **requestCount (number)**: Requests in the window.

- **baselineRequestCount (number)**: Requests in the baseline.

- **p95Ms (number)**: 95th percentile now.

- **baselineP95Ms (number)**: 95th percentile in the baseline.

- **p95DeltaPct (number)**: Change in the 95th percentile, in percent.

- **errorRate (number)**: Share of requests that failed now, from 0 to 1.

- **baselineErrorRate (number)**: The same in the baseline.

- **errorRateDelta (number)**: The difference.

- **totalMs (number)**: Time consumed now.

- **baselineTotalMs (number)**: Time consumed in the baseline.

- **score (number)**: The ranking score: latency and error movement weighted by traffic.

- **baseline (string)**: The baseline used.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/regressions \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'startTime=2026-10-19T14:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-19T14:40:00.000Z' \
  --data-urlencode 'baseline=weekAgo'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  startTime: '2026-10-19T14:00:00.000Z',
  endTime: '2026-10-19T14:40:00.000Z',
  baseline: 'weekAgo',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/regressions?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "baseline": "weekAgo",
  "points": [
    {
      "endpoint": "/v1/payments/{payment_id}/capture",
      "baseline": "weekAgo",
      "requestCount": 96,
      "baselineRequestCount": 91,
      "p95Ms": 3980,
      "baselineP95Ms": 310,
      "p95DeltaPct": 1183.9,
      "errorRate": 0.44,
      "baselineErrorRate": 0.01,
      "errorRateDelta": 0.43,
      "totalMs": 241200,
      "baselineTotalMs": 21800,
      "score": 912.4
    }
  ]
}
```

## Distributed trace

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/trace`

Returns every captured request that belongs to one distributed trace, in time order, across buckets and services. Each request is stamped with its trace id when it is captured: from the incoming `traceparent` header when there is one.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Query parameters

- **traceId (query, string, required)**:
  The trace id.

- **startTime (query, string, required)**:
  Start of the range to search.

- **endTime (query, string, required)**:
  End of the range to search.

- **environmentSid (query, string)**:
  Only this environment.

- **bucketSid (query, string)**:
  Only this bucket.

- **limit (query, integer, default 100)**:
  Requests to return, 1 to 1000.

### Response

- **traceId (string, required)**:
  The trace id.

- **points (object[], required)**:
  The requests, oldest first: `dt` (when it started), `sid`, `endpoint`, `method`, `host`, `path`, `direction`, `bucketSid`, `environmentSid`, `statusCode`, `durationMs` and `spanCount`. Use `sid` with [Get request](https://www.apitraffic.io/docs/api-reference/requests#get-request) for the detail.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/trace \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'traceId=4bf92f3577b34da6a3ce929d0e0e4736' \
  --data-urlencode 'startTime=2026-10-19T14:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-19T15:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  traceId: '4bf92f3577b34da6a3ce929d0e0e4736',
  startTime: '2026-10-19T14:00:00.000Z',
  endTime: '2026-10-19T15:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/trace?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
  "points": [
    {
      "dt": "2026-10-19T14:21:07.412Z",
      "sid": "req_2nA8fK3pQ7xV1mZ5tR9wB4cL6hY",
      "endpoint": "/v1/payments/{payment_id}/capture",
      "method": "POST",
      "host": "api.acme-store.example",
      "path": "/v1/payments/pi_3f9a1c7e2b4d6a/capture",
      "direction": "in",
      "bucketSid": "k3m9p2x",
      "environmentSid": "prd7k2",
      "statusCode": 502,
      "durationMs": 4012,
      "spanCount": 3
    },
    {
      "dt": "2026-10-19T14:21:07.418Z",
      "sid": "req_2cV9bN1mK4jH7gF3dS6aP8oI5uY",
      "endpoint": "/v1/payment_intents/{payment_intent_id}/capture",
      "method": "POST",
      "host": "payments.acme-pay.example",
      "path": "/v1/payment_intents/pi_3f9a1c7e2b4d6a/capture",
      "direction": "out",
      "bucketSid": "k3m9p2x",
      "environmentSid": "prd7k2",
      "statusCode": 504,
      "durationMs": 3995,
      "spanCount": 0
    }
  ]
}
```

## APM analytics

The operations below power the app's [APM analytics](https://www.apitraffic.io/docs/apm/analytics) pages. They rank span operations and endpoints on the server by total time, percentiles, calls, calls per request or regression score, chart one of them over time, compare it before and after a deploy, and return slow examples to open. Unlike the operations above, they report span-level detail and estimated call counts.

Every analytics response starts with the same fields:

- **sourceState (string, required)**:
  `ready`, or `absent` when the account has no data of this kind yet, so an empty answer is expected.

- **source (string, required)**:
  `hot_raw` (computed from individual spans) or `metrics` (from pre-aggregated metrics).

- **coverage (object, required)**:
  How much of the range was read: `status` (`full`, `partial` or `none`), `source`, `requested` and `effective` (the range actually read), `hotFrom`, `reason` (why it is partial, for example `metrics_lag` or `raw_window_capped`) and `foldedShare`.

- **estimator (string | null, required)**:
  How percentiles were computed: `tdigest`, `exact` or `histogram`.

- **unit (string, required)**:
  The unit of every duration in the answer: `us` (microseconds) or `ms`.

- **window (object, required)**:
  The range answered: `from`, `to` (rounded inward to minutes) and `snapSeconds`.

Answers about operations also carry `statementText` (whether the account stores statement text) and `dictionaryAvailable` (whether fingerprint details could be read in time).

All of them take `startTime` and `endTime` (required; `endTime` is exclusive), and optional `bucketSid` and `environmentSid`.

## Rank span operations

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/operations`

Ranks span operations (a fingerprint and its algorithm version) on the server, so slow but rare operations are not cut off by `limit`.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range (exclusive).

- **orderBy (query, string, default total)**:
  `total`, `p95`, `p99`, `calls`, `calls_per_request` (N+1 queries first), `error_rate` or `regression`.

- **limit (query, integer, default 50)**:
  Operations to return, 1 to 100.

- **endpoint (query, string)**:
  Only operations run by this inbound endpoint.

- **types (query, string)**:
  Only these span types, comma-separated: `db.query`, `redis`, `cache`, `http.out`, `queue`, `rpc`, `graphql`, `custom`.

- **minCalls (query, number, default 20)**:
  For `error_rate`, `calls_per_request` and `regression` ranking, ignore operations with fewer estimated calls (per side, for regression).

- **pivotAt (query, string)**:
  For `regression` ranking, the deploy time that splits before from after. Defaults to the middle of the range.

- **minRelativeIncrease (query, number, default 0.1)**:
  For `regression` ranking, the smallest p95 increase that counts (`0.1` is +10%).

- **fpVersion (query, integer)**:
  Only this fingerprint algorithm version.

### Response

The [common fields](#apm-analytics), `orderBy`, `limit`, `minCalls`, `pivotAt`, and:

- **points (object[], required)**:
  One entry per operation: `fingerprint`, `fpVersion`, `calls` (estimated), `rows` (spans read), `total`, `avg`, `p50`, `p95`, `p99`, `max`, `errors`, `errorRate`, `lastSeen`, `latestVersion` (the latest service version seen), `sampledRequests`, `callsPerRequest`, `type`, `system`, `op`, `target`, `name`, `db`, `host`, `regression` (with `regression` ranking) and `dictionary` (fingerprint details, or `null`).

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/operations \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'startTime=2026-10-19T00:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T00:00:00.000Z' \
  --data-urlencode 'orderBy=calls_per_request' \
  --data-urlencode 'types=db.query'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  startTime: '2026-10-19T00:00:00.000Z',
  endTime: '2026-10-20T00:00:00.000Z',
  orderBy: 'calls_per_request',
  types: 'db.query',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/operations?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "coverage": { "status": "full", "source": "hot_raw", "requested": {}, "hotFrom": null },
  "source": "hot_raw",
  "estimator": "exact",
  "unit": "us",
  "window": { "from": "2026-10-19T00:00:00.000Z", "to": "2026-10-20T00:00:00.000Z", "snapSeconds": 60 },
  "orderBy": "calls_per_request",
  "limit": 50,
  "minCalls": 20,
  "pivotAt": null,
  "statementText": true,
  "dictionaryAvailable": true,
  "points": [
    {
      "fingerprint": "fpr_5b8e2d7c1a9f4e3b",
      "fpVersion": 1,
      "calls": 21960,
      "rows": 21960,
      "total": 40406400,
      "avg": 1840,
      "p50": 1500,
      "p95": 4200,
      "p99": 7900,
      "max": 12100,
      "errors": 0,
      "errorRate": 0,
      "lastSeen": "2026-10-19T23:59:12.000Z",
      "latestVersion": "v2026.10.19",
      "sampledRequests": 1830,
      "callsPerRequest": 12,
      "type": "db.query",
      "system": "postgresql",
      "op": "SELECT",
      "target": "order_items",
      "name": "SELECT order_items",
      "db": "acme_store",
      "host": "db.acme.internal",
      "dictionary": null
    }
  ]
}
```

## Span operation trend

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/operations/trend`

Charts p50, p95, p99, calls and errors over time for one operation.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range (exclusive).

- **fingerprint (query, string, required)**:
  The operation's fingerprint (`fpr_…`).

- **fpVersion (query, integer, required)**:
  Its algorithm version, 1 to 255 (from [Rank span operations](#rank-span-operations); `1` when it has none).

- **endpoint (query, string)**:
  Only spans run by this inbound endpoint.

- **maxPoints (query, integer, default 120)**:
  At most this many periods, 2 to 500.

### Response

The [common fields](#apm-analytics), and:

- **step (object | null, required)**:
  The period width: `stepSeconds`, `fromSeconds`, `toSeconds`, and whether the first and last periods are partial.

- **points (object[], required)**:
  One entry per period: `bucket` (start, epoch seconds), `calls`, `rows`, `errors`, `total`, `p50`, `p95` and `p99`.

- **operation (object | null, required)**:
  What the operation is: `type`, `system`, `db`, `op`, `target`, `name`, `host`, `callSite`, `callSiteFn`, `firstSeenVersion`, `firstSeenAt`, `lastSeenAt`, `statement` and `callStack` (both `null` unless statement text is on).

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/operations/trend \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'fingerprint=fpr_5b8e2d7c1a9f4e3b' \
  --data-urlencode 'fpVersion=1' \
  --data-urlencode 'startTime=2026-10-19T00:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T00:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  fingerprint: 'fpr_5b8e2d7c1a9f4e3b',
  fpVersion: '1',
  startTime: '2026-10-19T00:00:00.000Z',
  endTime: '2026-10-20T00:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/operations/trend?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "source": "hot_raw",
  "unit": "us",
  "step": { "stepSeconds": 720, "fromSeconds": 1792368000, "toSeconds": 1792454400, "firstBucketPartial": false, "lastBucketPartial": false },
  "points": [
    { "bucket": 1792418400, "calls": 1104, "rows": 1104, "errors": 0, "total": 2030000, "p50": 1500, "p95": 4100, "p99": 7700 }
  ],
  "operation": { "type": "db.query", "system": "postgresql", "db": "acme_store", "op": "SELECT", "target": "order_items", "name": "SELECT order_items", "host": "db.acme.internal", "callSite": "src/repositories/orderRepository.js:48:22", "callSiteFn": "loadLineItems", "firstSeenVersion": "v2026.10.2", "firstSeenAt": "2026-10-02T10:04:51.000Z", "lastSeenAt": "2026-10-19T23:59:12.000Z", "statement": "SELECT * FROM order_items WHERE order_id = $1 AND line = $2", "callStack": null },
  "statementText": true,
  "dictionaryAvailable": true
}
```

The examples on this page leave out some of the common fields.

## Span operation heatmap

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/operations/heatmap`

Returns a latency heatmap for one operation: counts of spans per period and fixed latency band.

### Query parameters

The same as [Span operation trend](#span-operation-trend); `maxPoints` defaults to 60.

### Response

The [common fields](#apm-analytics), `step` and `operation` as in [Span operation trend](#span-operation-trend), and:

- **bounds (number[], required)**:
  The latency band edges, in `unit`.

- **cells (object[], required)**:
  One entry per non-empty cell: `bucket` (period start, epoch seconds), `latencyBucket` (the band's index), `lower`, `upper` and `count`.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/operations/heatmap \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'fingerprint=fpr_2a7e9c4b1d8f6e3a' \
  --data-urlencode 'fpVersion=1' \
  --data-urlencode 'startTime=2026-10-19T13:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-19T16:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  fingerprint: 'fpr_2a7e9c4b1d8f6e3a',
  fpVersion: '1',
  startTime: '2026-10-19T13:00:00.000Z',
  endTime: '2026-10-19T16:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/operations/heatmap?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { cells } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "us",
  "bounds": [1000, 10000, 100000, 1000000, 10000000],
  "cells": [
    { "bucket": 1792418400, "latencyBucket": 3, "lower": 1000000, "upper": 10000000, "count": 19 }
  ]
}
```

## Span operation regression

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/operations/regression`

Compares one operation before and after a deploy, split by time or by service version, with both distributions and a verdict.

### Query parameters

The fingerprint parameters of [Span operation trend](#span-operation-trend), plus:

- **pivotAt (query, string, required)**:
  The deploy time that splits before from after, inside the range.

- **version (query, string)**:
  Split by version instead: spans from this service version are "after" whenever they ran, other versions "before".

- **previousVersion (query, string)**:
  With `version`, only this version counts as "before".

- **unlabelled (query, string, default by_time)**:
  Spans without a service version: `by_time` (split by `pivotAt`) or `exclude`.

### Response

The [common fields](#apm-analytics), `operation`, and:

- **mode (string, required)**:
  `time` or `version`.

- **before (object | null, required)**:
  `calls`, `rows`, `errors`, `unlabelled`, `p50`, `p95`, `p99` and `hist` (counts per band in `bounds`). `after` has the same fields.

- **verdict (object | null, required)**:
  `regressed`, `score` (the p95 increase times the calls after; `null` with too little data), `deltaP95`, `ratioP95` and `reason` (`insufficient_data`, `below_threshold`, `improved` or `null`).

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/operations/regression \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'fingerprint=fpr_5b8e2d7c1a9f4e3b' \
  --data-urlencode 'fpVersion=1' \
  --data-urlencode 'pivotAt=2026-10-19T10:00:00.000Z' \
  --data-urlencode 'startTime=2026-10-18T10:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T10:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  fingerprint: 'fpr_5b8e2d7c1a9f4e3b',
  fpVersion: '1',
  pivotAt: '2026-10-19T10:00:00.000Z',
  startTime: '2026-10-18T10:00:00.000Z',
  endTime: '2026-10-20T10:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/operations/regression?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { verdict } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "us",
  "pivotAt": "2026-10-19T10:00:00.000Z",
  "mode": "time",
  "bounds": [1000, 10000, 100000],
  "before": { "calls": 20410, "rows": 20410, "errors": 0, "unlabelled": 0, "p50": 1400, "p95": 3900, "p99": 7100, "hist": [8100, 12200, 110, 0] },
  "after": { "calls": 21960, "rows": 21960, "errors": 0, "unlabelled": 0, "p50": 1500, "p95": 4200, "p99": 7900, "hist": [8300, 13500, 160, 0] },
  "verdict": { "score": 6588000, "deltaP95": 300, "ratioP95": 1.08, "regressed": false, "reason": "below_threshold" }
}
```

## Span operation examples

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/operations/examples`

Returns the slowest spans of one operation, and optionally some near a threshold such as its p95, to open in the request detail.

### Query parameters

The fingerprint parameters of [Span operation trend](#span-operation-trend), plus:

- **limit (query, integer, default 20)**:
  Slowest examples, 1 to 100.

- **nearDuration (query, number)**:
  Also return examples at or just above this duration (in the answer's `unit`), typically the p95 from the trend.

- **nearLimit (query, integer)**:
  How many of those, 1 to 50.

### Response

The [common fields](#apm-analytics), `operation`, and:

- **examples (object[], required)**:
  One entry per span: `kind` (slowest or near the threshold), `dt`, `requestDt`, `requestSid` (open it with [Get request](https://www.apitraffic.io/docs/api-reference/requests#get-request)), `spanSid`, `traceId`, `duration`, `ok`, `errorClass`, `statusCode`, `endpoint`, `method`, `serviceVersion` and `instanceSid`.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/operations/examples \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'fingerprint=fpr_2a7e9c4b1d8f6e3a' \
  --data-urlencode 'fpVersion=1' \
  --data-urlencode 'limit=5' \
  --data-urlencode 'startTime=2026-10-19T13:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-19T16:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  fingerprint: 'fpr_2a7e9c4b1d8f6e3a',
  fpVersion: '1',
  limit: '5',
  startTime: '2026-10-19T13:00:00.000Z',
  endTime: '2026-10-19T16:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/operations/examples?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { examples } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "us",
  "examples": [
    {
      "kind": "slowest",
      "dt": "2026-10-19T14:21:07.418Z",
      "requestDt": "2026-10-19T14:21:07.412Z",
      "requestSid": "req_2nA8fK3pQ7xV1mZ5tR9wB4cL6hY",
      "spanSid": "spn_02",
      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
      "duration": 3995000,
      "ok": false,
      "errorClass": "timeout",
      "statusCode": 504,
      "endpoint": "/v1/payments/{payment_id}/capture",
      "method": "POST",
      "serviceVersion": "v2026.10.19",
      "instanceSid": "ins_k8f2a1"
    }
  ]
}
```

## Rank endpoints

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/endpoints`

Ranks endpoints (template and method) on the server. With `direction=out`, ranks the outbound calls your API makes.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range (exclusive).

- **orderBy (query, string, default total)**:
  `total`, `p95`, `p99`, `calls`, `error_rate` or `regression`.

- **direction (query, string, default in)**:
  `in` (your API's endpoints) or `out` (calls it makes).

- **limit (query, integer, default 50)**:
  Endpoints to return, 1 to 100.

- **minCalls (query, number, default 20)**:
  As for [Rank span operations](#rank-span-operations).

- **pivotAt (query, string)**:
  As for [Rank span operations](#rank-span-operations).

- **minRelativeIncrease (query, number, default 0.1)**:
  As for [Rank span operations](#rank-span-operations).

### Response

The [common fields](#apm-analytics), `orderBy`, `limit`, `minCalls`, `pivotAt`, and:

- **points (object[], required)**:
  One entry per endpoint: `endpoint`, `method`, `calls`, `rows`, `total`, `avg`, `p50`, `p95`, `p99`, `max`, `errors`, `errorRate`, `clientErrors`, `lastSeen`, `latestVersion` and, with `regression` ranking, `regression`.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/endpoints \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'orderBy=p95' \
  --data-urlencode 'startTime=2026-10-19T00:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T00:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({ orderBy: 'p95', startTime: '2026-10-19T00:00:00.000Z', endTime: '2026-10-20T00:00:00.000Z' });
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/endpoints?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "ms",
  "orderBy": "p95",
  "limit": 50,
  "minCalls": 20,
  "pivotAt": null,
  "points": [
    {
      "endpoint": "/v1/payments/{payment_id}/capture",
      "method": "POST",
      "calls": 402,
      "rows": 402,
      "total": 246180,
      "avg": 612.4,
      "p50": 240,
      "p95": 3980,
      "p99": 4060,
      "max": 4120,
      "errors": 61,
      "errorRate": 0.152,
      "clientErrors": 0,
      "lastSeen": "2026-10-19T23:57:40.000Z",
      "latestVersion": "v2026.10.19"
    }
  ]
}
```

## Endpoint trend, heatmap, regression and examples

Four operations do for one endpoint what the operation versions above do for one span operation. Instead of `fingerprint` and `fpVersion`, they take:

- **endpoint (query, string, required)**:
  The endpoint template, for example `/v1/orders/{order_id}`.

- **method (query, string, required)**:
  The HTTP method.

- **direction (query, string, default in)**:
  `in` or `out`.

Their other parameters and responses match the operation versions, without `operation`, `statementText` and `dictionaryAvailable`.

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/endpoints/trend`

Like [Span operation trend](#span-operation-trend): p50, p95, p99, calls and errors over time.

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/endpoints/heatmap`

Like [Span operation heatmap](#span-operation-heatmap).

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/endpoints/regression`

Like [Span operation regression](#span-operation-regression), with `pivotAt` required.

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/endpoints/examples`

Like [Span operation examples](#span-operation-examples): the slowest requests to the endpoint.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/endpoints/trend \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'endpoint=/v1/payments/{payment_id}/capture' \
  --data-urlencode 'method=POST' \
  --data-urlencode 'startTime=2026-10-19T13:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-19T16:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  endpoint: '/v1/payments/{payment_id}/capture',
  method: 'POST',
  startTime: '2026-10-19T13:00:00.000Z',
  endTime: '2026-10-19T16:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/endpoints/trend?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "ms",
  "step": { "stepSeconds": 120, "fromSeconds": 1792414800, "toSeconds": 1792425600, "firstBucketPartial": false, "lastBucketPartial": false },
  "points": [
    { "bucket": 1792418520, "calls": 4, "rows": 4, "errors": 3, "total": 15800, "p50": 3990, "p95": 4110, "p99": 4120 }
  ]
}
```

## Rank regressions

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/regressions`

Returns the operations or endpoints that got slower after a deploy time, ranked by regression score.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range (exclusive).

- **kind (query, string, default operation)**:
  `operation` or `endpoint`.

- **pivotAt (query, string)**:
  The deploy time. Defaults to the middle of the range.

- **direction (query, string, default in)**:
  With `kind=endpoint`, `in` or `out`.

- **endpoint (query, string)**:
  With `kind=operation`, only operations run by this endpoint.

- **types (query, string)**:
  With `kind=operation`, only these span types (comma-separated).

- **limit (query, integer, default 50)**:
  Results, 1 to 100.

- **minCalls (query, number, default 20)**:
  Ignore results with fewer estimated calls on either side.

- **minRelativeIncrease (query, number, default 0.1)**:
  The smallest p95 increase that counts.

### Response

The [common fields](#apm-analytics), `orderBy`, `limit`, `minCalls`, `pivotAt`, and `points`: entries shaped as in [Rank span operations](#rank-span-operations) or [Rank endpoints](#rank-endpoints), each with `regression`.

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/regressions \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'kind=endpoint' \
  --data-urlencode 'pivotAt=2026-10-19T10:00:00.000Z' \
  --data-urlencode 'startTime=2026-10-18T10:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T10:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  kind: 'endpoint',
  pivotAt: '2026-10-19T10:00:00.000Z',
  startTime: '2026-10-18T10:00:00.000Z',
  endTime: '2026-10-20T10:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/regressions?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "ms",
  "orderBy": "regression",
  "limit": 50,
  "minCalls": 20,
  "pivotAt": "2026-10-19T10:00:00.000Z",
  "points": [
    {
      "endpoint": "/v1/payments/{payment_id}/capture",
      "method": "POST",
      "calls": 402,
      "p95": 3980,
      "errorRate": 0.152,
      "regression": {}
    }
  ]
}
```

## Rank dependencies

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/apm/analytics/dependencies`

Ranks what your API depends on (databases, caches, HTTP APIs and queues) by peer or by target, with latency and the mix of error types.

### Query parameters

- **startTime (query, string, required)**:
  Start of the range.

- **endTime (query, string, required)**:
  End of the range (exclusive).

- **granularity (query, string, default peer)**:
  `peer`: one row per type, system, host and database. `target`: one row per table or outbound endpoint on it.

- **orderBy (query, string, default total)**:
  `total`, `p95`, `calls`, `calls_per_request` or `error_rate`.

- **endpoint (query, string)**:
  Only dependencies of this inbound endpoint.

- **types (query, string)**:
  Only these span types (comma-separated).

- **limit (query, integer, default 50)**:
  Results, 1 to 100.

- **minCalls (query, number, default 20)**:
  For `calls_per_request` and `error_rate` ranking, ignore dependencies with fewer estimated calls.

### Response

The [common fields](#apm-analytics), and `points`: `type`, `system`, `host`, `db`, `target`, `op`, `calls`, `rows`, `total`, `avg`, `p50`, `p95`, `p99`, `max`, `errors`, `errorRate`, `lastSeen`, `latestVersion`, `sampledRequests`, `callsPerRequest` and `errorClasses` (errors by class).

```bash cURL
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/apm/analytics/dependencies \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'types=http.out' \
  --data-urlencode 'orderBy=error_rate' \
  --data-urlencode 'startTime=2026-10-19T00:00:00.000Z' \
  --data-urlencode 'endTime=2026-10-20T00:00:00.000Z'
```

```js Node.js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({
  types: 'http.out',
  orderBy: 'error_rate',
  startTime: '2026-10-19T00:00:00.000Z',
  endTime: '2026-10-20T00:00:00.000Z',
});
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/apm/analytics/dependencies?${params}`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { points } = await response.json();
```

```json 200
{
  "sourceState": "ready",
  "unit": "us",
  "orderBy": "error_rate",
  "points": [
    {
      "type": "http.out",
      "system": "http",
      "host": "payments.acme-pay.example",
      "db": "",
      "target": "",
      "op": "",
      "calls": 1020,
      "rows": 1020,
      "total": 612000000,
      "avg": 600000,
      "p50": 210000,
      "p95": 3990000,
      "p99": 4010000,
      "max": 4020000,
      "errors": 61,
      "errorRate": 0.0598,
      "lastSeen": "2026-10-19T23:57:40.000Z",
      "latestVersion": "v2026.10.19",
      "sampledRequests": 1020,
      "callsPerRequest": 1,
      "errorClasses": { "timeout": 47, "5xx": 14 }
    }
  ]
}
```

## Errors

| Status | Code | Meaning |
| --- | --- | --- |
| `400` | `1000` | A parameter is missing or invalid, for example `limit` above 1000. |
| `403` | `2221` | The plan does not include APM. |
| `502` | `5105` | The query failed. Retry. |
| `503` | `5102`, `5103`, `5104` | Analytics are temporarily unavailable. Retry after `Retry-After` seconds. |
| `504` | `5101` | The query took too long. Narrow the range and retry. |

## Related

- [How APM works](https://www.apitraffic.io/docs/apm/overview):
    What APM measures and how to read it.

- [Spans API](https://www.apitraffic.io/docs/api-reference/spans):
    The operations behind the time split.
