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

# Detect anomalies in a metrics timeseries

The `query` field takes a timeseries query. For selectors and fields, see [Querying metrics](https://docs.appsignal.com/api/v2/metrics.md#query-a-timeseries).

```yaml POST /api/v2/metrics/anomaly theme={null}
openapi: 3.1.0
info:
  title: AppSignal V2 API
  description: >-
    REST API for metrics, traces, logs, Kubernetes monitoring, and deployment
    tracking.
  license:
    name: ''
  version: 0.1.0
paths:
  /api/v2/metrics/anomaly:
    post:
      tags:
        - Metrics
      summary: Detect anomalies in a metrics timeseries
      operationId: anomaly
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnomalyRequest'
            example:
              query:
                site_id: abc123
                from: '2024-01-01T00:00:00Z'
                to: '2024-01-08T00:00:00Z'
                resolution: HOURLY
                select:
                  - name: disk_usage
                    field: GAUGE
                    tags:
                      hostname: server-1
              detector: trend
              config:
                ceiling: 100
        required: true
      responses:
        '200':
          description: The fetched series and its detections.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnomalyResponse'
        '400':
          description: Invalid query, including a window longer than 30 days.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequestResponse'
        '401':
          description: Missing or invalid authentication token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Route or resource not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: External query concurrency limit exceeded; retry shortly.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TooManyRequestsResponse'
        '500':
          description: Unhandled server-side failure.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - bearer_auth: []
        - token_query: []
components:
  schemas:
    Aggregation:
      type: string
      description: >-
        The aggregation function applied when combining multiple values within a
        time bucket.


        Serialized as uppercase strings (e.g. `"SUM"`, `"AVERAGE"`). When no
        aggregation is

        explicitly set on a selector, a default is chosen based on the [`Field`]
        type.
      enum:
        - SUM
        - AVERAGE
        - MIN
        - MAX
        - FIRST
        - LAST
    AnomalyConfig:
      type: object
      description: >-
        Detector tuning for one anomaly run; each detector reads only its own
        fields.
      properties:
        ceiling:
          type:
            - number
            - 'null'
          format: double
          description: >-
            The value a series is projected to cross, e.g. `100` for disk-usage
            %. The trend

            and time_to_threshold detectors produce no detections without it.
        min_fit_quality:
          type: number
          format: double
          description: >-
            Minimum R² below which the trend detector does not trust a
            projection.
          default: 0.8
          maximum: 1
          minimum: 0
        spike_threshold:
          type: number
          format: double
          description: Modified z-score at/above which the spike detector flags a point.
          default: 3.5
          exclusiveMinimum: 0
        baseline_until:
          type:
            - integer
            - 'null'
          format: int64
          description: >-
            Unix seconds; spike and rate baselines use only points before it,
            and only points

            at/after it are flagged (e.g. a deploy time). Unset: the whole
            window.
        changepoint_threshold:
          type: number
          format: double
          description: >-
            MAD-scaled shift magnitude at/above which the changepoint detector
            reports a level shift.
          default: 3.5
          exclusiveMinimum: 0
        horizon_minutes:
          type:
            - number
            - 'null'
          format: double
          description: >-
            The time_to_threshold detector fires when `ceiling` is projected to
            be crossed

            within this many minutes; it produces no detections without it.
          exclusiveMinimum: 0
        rate_numerator:
          type:
            - string
            - 'null'
          description: >-
            Rate detector numerator metric (event count), e.g. `"error_count"`.
            Required,

            with `rate_denominator`, for the rate detector to produce
            detections.
        rate_denominator:
          type:
            - string
            - 'null'
          description: >-
            Rate detector denominator metric (throughput), e.g.
            `"trace_duration"` selected

            with the `COUNT` field, paired with `rate_numerator` by tags.
        rate_threshold:
          type: number
          format: double
          description: Proportion z-score at/above which the rate detector flags a bucket.
          default: 3.5
          exclusiveMinimum: 0
        rate_min_denominator:
          type: number
          format: double
          description: Minimum throughput a bucket needs before the rate detector tests it.
          default: 20
          minimum: 1
    AnomalyPoint:
      type: object
      description: >-
        A single anomalous point flagged by a point-anomaly detector (e.g.
        spike).


        The changepoint detector reuses this struct to describe a detected level
        shift,

        reinterpreting the fields: `at` is the shift boundary, `baseline` the
        robust level

        *before* the shift, `value` the robust level *after* it, and `z_score`
        the MAD-scaled

        shift magnitude (sign = direction: positive = stepped up, negative =
        stepped down).


        The rate detector likewise reuses it for an anomalous rate bucket: `at`
        is the bucket,

        `value` the observed rate (`numerator / denominator`), `baseline` the
        robust baseline

        rate, and `z_score` the one-sample proportion z (sign = direction:
        positive = rate rose,

        negative = fell).
      required:
        - at
        - value
        - z_score
        - baseline
      properties:
        at:
          type: integer
          format: int64
          description: >-
            Unix-seconds timestamp of the anomalous point (spike), shift
            boundary (changepoint)

            or rate bucket (rate).
        value:
          type: number
          format: double
          description: >-
            The point's value (spike), the robust level *after* the shift
            (changepoint) or the

            observed rate (rate).
        z_score:
          type: number
          format: double
          description: >-
            Robust modified z-score (Iglewicz–Hoaglin) for a spike, the
            MAD-scaled shift

            magnitude for a changepoint, or the one-sample proportion z for a
            rate; its sign

            carries direction (positive = above the baseline / stepped up / rate
            rose, negative

            = below it / stepped down / rate fell).
        baseline:
          type: number
          format: double
          description: >-
            Robust baseline the point deviates from (spike), the robust level
            *before* the

            shift (changepoint) or the robust baseline rate (rate).
    AnomalyRequest:
      type: object
      description: The series to analyse, the detector to run and its tuning.
      required:
        - query
      properties:
        query:
          $ref: '#/components/schemas/TimeseriesQuery'
          description: >-
            The series to analyse; at most 30 days. Empty buckets are never
            filled, and

            projections are measured from `to`.
        detector:
          oneOf:
            - $ref: '#/components/schemas/DetectorKind'
              description: Which detection algorithm to run.
          default: trend
        config:
          $ref: '#/components/schemas/AnomalyConfig'
          description: Detector tuning (e.g. the `ceiling` a trend is projected to cross).
    AnomalyResponse:
      type: object
      description: The analysed series and its detections.
      required:
        - series
        - detections
      properties:
        series:
          $ref: '#/components/schemas/Timeseries'
          description: The fetched series, to overlay the detections on.
        detections:
          type: array
          items:
            $ref: '#/components/schemas/Detection'
          description: >-
            The detections produced by the detector, one per anomalous series
            (possibly empty).
    BadRequestResponse:
      type: object
      description: >-
        Standard body for HTTP 400 Bad Request responses. Branch on the stable
        `error` slug, display `message` as-is, and read per-error structured
        data from `details`.
      required:
        - error
        - message
      properties:
        error:
          type: string
          description: Stable, machine-readable slug identifying the specific error case.
        message:
          type: string
          description: Human-readable message. Safe to log or display to end users.
        details:
          description: >-
            Per-error structured payload. Shape varies by
            [`error`](Self::error).
    Detection:
      type: object
      description: A single anomaly detected on one series.
      required:
        - kind
        - series_id
        - score
        - severity
        - explanation
      properties:
        kind:
          $ref: '#/components/schemas/DetectorKind'
          description: Which detector produced this detection.
        series_id:
          type: string
          description: The `id` of the series this detection refers to.
        score:
          type: number
          format: double
          description: >-
            Detector-specific score: fit quality `0.0..=1.0` (trend), urgency
            `0.0..=1.0`

            (time_to_threshold) or the max `|z-score|` (spike, changepoint,
            rate). Compare

            only within one `kind`; `severity` is comparable across detectors.
        severity:
          $ref: '#/components/schemas/Severity'
          description: Severity bucket.
        projection:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/Projection'
              description: >-
                Forward projection, from the trend and time_to_threshold
                detectors.
        points:
          type: array
          items:
            $ref: '#/components/schemas/AnomalyPoint'
          description: >-
            The series' flagged points, from the spike, changepoint and rate
            detectors.
        explanation:
          type: string
          description: >-
            Human-readable explanation, e.g. "disk_usage is projected to cross
            100 in ~6 days".
    DetectorKind:
      type: string
      description: >-
        Which detection algorithm produced (or is requested to produce) a
        result.
      enum:
        - trend
        - spike
        - changepoint
        - time_to_threshold
        - rate
    ErrorResponse:
      type: object
      description: Error body returned for 401, 404 and 500 responses.
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
    Field:
      type: string
      description: >-
        The specific measurement within a metric to retrieve.


        A gauge metric only has a [`Gauge`](Self::Gauge) field; a counter metric
        only has a

        [`Counter`](Self::Counter) field; a measurement metric has statistical
        fields such as

        [`Mean`](Self::Mean), [`Count`](Self::Count), [`Min`](Self::Min),
        [`Max`](Self::Max)

        and percentiles.


        Serialized as uppercase strings (e.g. `"GAUGE"`, `"P95"`).
      enum:
        - GAUGE
        - COUNTER
        - MEAN
        - COUNT
        - MIN
        - MAX
        - P99
        - P95
        - P90
        - P80
        - P75
        - P70
        - P60
        - P50
        - P40
        - P30
        - P20
        - P10
    FillMode:
      type: string
      description: >-
        How missing data points (empty time buckets) are filled when assembling
        a series.
      enum:
        - ZERO
        - PREVIOUS
        - NONE
    Point:
      type: object
      description: >-
        A single data point in a timeseries, representing a value at a specific
        moment in time.
      required:
        - timestamp
        - value
      properties:
        timestamp:
          type: string
          format: date-time
          description: >-
            The moment in time this data point represents, aligned to the
            query's timeframe resolution.
        value:
          type: number
          format: double
          description: The numeric metric value at this timestamp.
    Projection:
      type: object
      description: A forward projection of a fitted linear trend toward a ceiling.
      required:
        - slope_per_second
        - fit_quality
        - ceiling
        - cross_at
        - seconds_to_cross
      properties:
        slope_per_second:
          type: number
          format: double
          description: Fitted slope, in value-units per second.
        fit_quality:
          type: number
          format: double
          description: >-
            Goodness-of-fit (R², `0.0..=1.0`) of the linear fit the projection
            rests on.
        ceiling:
          type: number
          format: double
          description: The ceiling the series is projected to cross.
        cross_at:
          type: integer
          format: int64
          description: >-
            Unix-seconds timestamp at which the series is projected to cross the
            ceiling.
        seconds_to_cross:
          type: integer
          format: int64
          description: >-
            Seconds from the reference time (`now`) until the projected
            crossing.
    Resolution:
      type: string
      description: Time resolution that metrics can be returned in
      enum:
        - HOURLY
        - MINUTELY
        - DAILY
    Serie:
      type: object
      description: >-
        A single timeseries: a named sequence of points that share the same tags
        and field.
      required:
        - id
        - name
        - tags
        - max
        - min
        - field
        - data
      properties:
        id:
          type: string
          description: >-
            Unique identifier for this series, composed of the metric name,
            sorted tags and field

            (e.g. `"cpu_usage{hostname=frontend1};GAUGE"`).
        name:
          type: string
          description: The metric name (e.g. `"cpu_usage"`, `"transaction_duration"`).
        tags:
          type: object
          description: >-
            Tag key-value pairs that distinguish this series from others with
            the same name

            (e.g. `{"hostname": "frontend1"}`).
          additionalProperties:
            type: string
          propertyNames:
            type: string
        max:
          type: number
          format: double
          description: The maximum value across all data points in this series.
        min:
          type: number
          format: double
          description: The minimum value across all data points in this series.
        field:
          $ref: '#/components/schemas/Field'
          description: >-
            The type of measurement this series represents (e.g. gauge, mean, a
            percentile).
        data:
          type: array
          items:
            $ref: '#/components/schemas/Point'
          description: >-
            The ordered sequence of data points, aligned to the query's
            timeframe resolution.
    Severity:
      type: string
      description: >-
        Severity bucket for a detection, derived from how imminent / large the
        anomaly is.
      enum:
        - info
        - warning
        - critical
    Timeseries:
      type: object
      description: >-
        A collection of series over a time range, aligned to the given
        resolution.
      required:
        - resolution
        - from
        - to
        - series
      properties:
        resolution:
          $ref: '#/components/schemas/Resolution'
          description: >-
            The time interval between consecutive data points (e.g. one minute,
            one hour).
        from:
          type: string
          format: date-time
          description: Start of the queried time range (inclusive).
        to:
          type: string
          format: date-time
          description: End of the queried time range (inclusive).
        series:
          type: array
          items:
            $ref: '#/components/schemas/Serie'
          description: The individual timeseries that matched the query.
    TimeseriesQuery:
      type: object
      description: Query for fetching timeseries metric data, used to populate graphs.
      required:
        - from
        - to
        - site_id
        - select
      properties:
        from:
          type: string
          format: date-time
          description: Start of the time range to query (inclusive).
        to:
          type: string
          format: date-time
          description: End of the time range to query (inclusive).
        resolution:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/Resolution'
              description: >-
                The desired interval between data points. When `None`, a
                resolution is

                automatically chosen based on the time range.
        site_id:
          type: string
          description: The site to fetch metrics for.
        select:
          type: array
          items:
            $ref: '#/components/schemas/TimeseriesSelector'
          description: Selectors that define which metrics and fields to fetch.
        limit:
          type:
            - integer
            - 'null'
          format: int32
          description: >-
            Maximum number of unique series to return. When `None`, no limit is
            applied.
    TimeseriesSelector:
      type: object
      description: >-
        Selects a specific metric, field and tag combination to include in a
        timeseries response.
      required:
        - name
        - tags
        - field
      properties:
        name:
          type: string
          description: >-
            The metric name to query (e.g. `"cpu_usage"`,
            `"transaction_duration"`).
        tags:
          type: object
          description: 'Tag key-value pairs to filter on (e.g. `{"hostname": "frontend1"}`).'
          additionalProperties:
            type: string
          propertyNames:
            type: string
        field:
          $ref: '#/components/schemas/Field'
          description: >-
            The specific measurement field to retrieve (e.g. `GAUGE`, `MEAN`,
            `P95`).
        aggregation:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/Aggregation'
              description: >-
                The aggregation function to apply when combining values within a
                time bucket.

                When omitted, a default is chosen based on the field (e.g. `SUM`
                for counters,

                `AVERAGE` for percentiles).
        draw_null_as_zero:
          type: boolean
          description: >-
            Legacy fill policy: `true` fills missing data points with `0.0`,
            `false` carries

            the previous value forward. Superseded by `fill`.
          default: true
        fill:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/FillMode'
              description: >-
                Preferred fill policy; takes precedence over `draw_null_as_zero`
                when set.
    TooManyRequestsResponse:
      type: object
      description: Error body returned for 429 responses.
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
        suggestion:
          type:
            - string
            - 'null'
          description: >-
            A cheaper way to write the request's filter. Only the trace list

            endpoints set it, and only for a filter with a known indexed
            rewrite.
  securitySchemes:
    bearer_auth:
      type: http
      scheme: bearer
      description: '`Authorization: Bearer <token>`'
    token_query:
      type: apiKey
      in: query
      name: token
      description: >-
        Alternative to the Authorization header: pass the token as a
        `?token=<token>` query parameter.
```


## API Specification

The full API specification for this endpoint is available in the [documentation index](https://docs.appsignal.com/llms.txt).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.