Networking Minerva User Guide

Retrieve Time Series Data with the REST API

Retrieve measurements, anomaly detections, rare syslogs, and correlated incidents from NVIDIA Minerva through the REST API.

Attribute

Value

Preferred method

POST

Query endpoint

/minerva/api/poststream

Alternate transport

GET /minerva/api/stream

Request and response format

application/json

Authentication

Deployment API key in x-api-key

The examples use illustrative devices and UTC windows. Available fields, retained data, and permissions depend on your installation.

Authentication and Headers

Use the HTTPS origin for your installation, without an API path or trailing slash.

Bash
export MINERVA_BASE='https://minerva.example.com'
# Set MINERVA_API_KEY through your approved secret-management mechanism.

Header

Value

x-api-key

Deployment API key

Content-Type

application/json for a JSON request body

Accept

application/json

Keep API keys outside source files, saved requests, and shared output. Use the certificate trust configuration for your installation.

Use /minerva/api for these requests. Time-series query endpoints do not add a /v2 or /v3 segment.

Discover Datasources and Fields

A datasource identifies a collection in the time-series database. Discover the available collections before you construct a query.

Bash
curl --fail-with-body --silent --show-error \
  "$MINERVA_BASE/minerva/api/tsdatasources" \
  -H "x-api-key: $MINERVA_API_KEY" \
  -H 'Accept: application/json'

Datasource entries can contain name and properties. A listed datasource does not establish that every metric exists or contains recent data.

Method and path

Purpose

GET /minerva/api/tsdatasources

List datasource metadata

GET /minerva/api/models/

List model names

GET /minerva/api/models/?name=MODEL_NAME

Read a model definition

GET /minerva/api/models/dimensions?name=MODEL_NAME

Read identity and filter fields

GET /minerva/api/models/metrics?name=MODEL_NAME

Read metric definitions

GET /minerva/api/models/keys?name=MODEL_NAME

Read identity keys

GET /minerva/api/models/model_name?tsdb_name=TSDB_NAME

Find a model for a time-series name

GET /minerva/api/models/tsdb_name?name=MODEL_NAME

Find a time-series name for a model

Use returned names in these requests. A model name and datasource name are not necessarily identical.

Datasource

Common contents

interface_v1

Cumulus interface measurements, including rawBer

interface_nvlink_v1

NVLink interface measurements

system_v1

Device and component measurements

histogram_v1

Histograms and distributions

raw_v1

Events, anomaly summaries, incident summaries, and job events

anomaly_v1

Anomaly index records, including rare-log detections

syslog_v1

Stored syslog records

raw_hourly_v1

Hourly event rollups, where configured

Example: RawBER on a Cumulus Interface

Use this query to examine link quality on one Cumulus interface over an hour. It returns the maximum RawBER value in each minute.

The metric name is rawBer, with a lowercase initial letter. It is a gauge, so do not sum it or calculate counter deltas.

This example selects device leaf-01, interface swp1, and the Cumulus switch measurement source. Replace the device, interface, and interval.

Save this body as rawber-request.json:

JSON
{
  "query": "select * from timeseries",
  "tstype": "groupBy",
  "granularity": 60000,
  "tsparams": {
    "queryType": "groupBy",
    "dataSource": "interface_v1",
    "intervals": ["2026-10-29T12:00:00Z/2026-10-29T13:00:00Z"],
    "granularity": {"type": "duration", "duration": 60000},
    "dimensions": ["deviceName", "ifName", "eventSource"],
    "filter": {
      "type": "and",
      "fields": [
        {"type": "selector", "dimension": "namespace", "value": "prod"},
        {"type": "selector", "dimension": "type", "value": "interface"},
        {"type": "selector", "dimension": "eventSource", "value": "switch"},
        {"type": "selector", "dimension": "deviceName", "value": "leaf-01"},
        {"type": "selector", "dimension": "ifName", "value": "swp1"}
      ]
    },
    "aggregations": [
      {"type": "doubleMax", "name": "rawBerMax", "fieldName": "rawBer"}
    ],
    "limitSpec": {"type": "default", "limit": 1000},
    "context": {"skipEmptyBuckets": true}
  }
}
Bash
curl --fail-with-body --silent --show-error \
  --request POST "$MINERVA_BASE/minerva/api/poststream" \
  -H "x-api-key: $MINERVA_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data-binary @rawber-request.json > rawber-response.json

The query preserves zero values. A null value means RawBER is unavailable for that result. An absent bucket does not mean zero.

A bucket maximum is not an individual raw sample. Smaller query buckets cannot recover detail lost through prior aggregation.

Request Fields

Field

Meaning

query

Fixed request selector, such as select * from timeseries

tstype

Response format selector. Match tsparams.queryType.

granularity

Bucket size in milliseconds. Keep it consistent with the query.

tsparams.dataSource

Datasource name

tsparams.intervals

UTC start/end pairs, with an inclusive start and exclusive end

tsparams.dimensions

Identity fields to retain in each result

tsparams.filter

Device, interface, source, and other scope restrictions

tsparams.aggregations

Metric calculations within each bucket

tsparams.limitSpec

Result limit and optional ordering for groupBy

The request selector strings are part of the API contract. Preserve their spelling and case.

Metric Response

Measurement results appear in entries[].object.content:

JSON
{
  "entries": [
    {
      "object": {
        "content": {
          "timestamp": "2026-10-29T12:00:00.000Z",
          "dimensions": {
            "deviceName": "leaf-01",
            "ifName": "swp1",
            "eventSource": "switch"
          },
          "measures": {"rawBerMax": 0.000001}
        }
      }
    }
  ]
}

This illustrative response omits other envelope fields. Use the content timestamp for the measurement bucket, rather than the envelope creation time.

Other Metric Queries

Query type

Purpose

Limit

groupBy

Group measurements by identity fields and time buckets

limitSpec.limit

timeseries

Aggregate each bucket without identity grouping

Time interval and bucket size

topN

Rank one dimension within each bucket

threshold

scan

Retrieve stored rows with explicit columns

limit

Use each query type's request fields. For timeseries, omit dimensions and limitSpec. For topN, use dimension, metric, and threshold.

For scan, set resultFormat to list and specify columns. Retain dimensions for response classification.

Add this object to virtualColumns. Include timestamp in columns, but exclude it from dimensions:

JSON
{"name": "timestamp", "type": "expression", "expression": "timestamp_format(__time)"}

Use each metric's declared aggregation. Interval-delta counters require sums, gauges require a suitable minimum, maximum, or average, and distributions require their declared calculation.

Retrieve Rare Syslogs and Anomaly Details

Rare syslogs are anomaly detections derived from log messages. They differ from an unrestricted export of stored syslogs.

Send this body to POST /minerva/api/poststream:

JSON
{
  "query": "select * from mv-anomaly",
  "tstype": "groupBy",
  "granularity": 1000,
  "tsparams": {
    "queryType": "groupBy",
    "dataSource": "anomaly_v1",
    "intervals": ["2026-10-29T12:00:00Z/2026-10-29T13:00:00Z"],
    "granularity": {"type": "duration", "duration": 1000},
    "dimensions": ["key", "anomalyType"],
    "filter": {
      "type": "and",
      "fields": [
        {"type": "selector", "dimension": "deviceName", "value": "leaf-01"},
        {"type": "selector", "dimension": "eventType", "value": "Anomaly"},
        {"type": "selector", "dimension": "anomalyType", "value": "text"},
        {"type": "selector", "dimension": "type", "value": "anomalyRareSyslogPerAppSev"}
      ]
    },
    "limitSpec": {
      "type": "default",
      "limit": 100,
      "columns": [
        {"dimension": "key", "direction": "ascending"},
        {"dimension": "anomalyType", "direction": "ascending"}
      ]
    }
  }
}

Save the body as anomalies-request.json, then use the same curl command with that filename.

For other anomaly types, remove the anomalyType and type filters. Retain the device, time interval, and result limit.

This detail query requires groupBy, one interval, and a positive duration. Preserve key and anomalyType in the dimensions.

The API selects anomaly identities from the time-series database and retrieves their full detection records. Missing detail records can reduce the result count.

Anomaly content is an object with fields such as alarmId, alarmType, subType, dimensions, and attrs.

Use attrs.epoch for the detection time in milliseconds since the Unix epoch. Retained dimensions can use names such as DeviceName and Description.

For stored event summaries, use select * from timeseries with raw_v1. Filter eventType to Anomaly, Incident, or eventThreshold as appropriate.

These values are case-sensitive. Summary rows do not replace full detection records or incident membership.

Retrieve Correlated Incidents

Send this body to the same query endpoint:

JSON
{
  "query": "select * from correlated_alarm",
  "tstype": "groupBy",
  "granularity": 60000,
  "tsparams": {
    "queryType": "groupBy",
    "dataSource": "raw_v1",
    "intervals": ["2026-10-29T12:00:00Z/2026-10-29T13:00:00Z"],
    "granularity": {"type": "duration", "duration": 60000},
    "dimensions": ["key"],
    "filter": {"type": "selector", "dimension": "eventType", "value": "Incident"},
    "aggregations": [{"type": "count", "name": "count_Sum"}],
    "limitSpec": {"type": "default", "limit": 100}
  }
}

Add the scope filters required for your installation. Use one interval, retain key, and keep both granularity values consistent.

To retrieve one incident or event, use its exact returned eventId:

JSON
{"query": "select * from event", "eventId": "INCIDENT_ID_FROM_RESPONSE"}

To retrieve the incident's member events:

JSON
{"query": "select * from alarm where correlatedAlarmId=INCIDENT_ID_FROM_RESPONSE"}

Replace the identifier without quotes inside the selector string. The optional envelope field group_id restricts members to an exact network graph group.

Membership follows the incident's eventIds. It does not accept an independent time window.

Incident and member-event content is a JSON-encoded string. Decode it once, unlike the object content used for measurements and anomalies:

Python
import json

for entry in response.get("entries") or []:
    content = entry["object"]["content"]
    if isinstance(content, str):
        content = json.loads(content)
    print(content)

An incident can include incident.numberEvents and incident.eventIds. Compare returned members with those fields and report missing detail records.

Alternate Transport and Job Scope

GET /minerva/api/stream accepts the same envelope fields as query parameters. Encode tsparams as JSON, then URL-encode each parameter.

Bash
curl --fail-with-body --silent --show-error --get \
  "$MINERVA_BASE/minerva/api/stream" \
  -H "x-api-key: $MINERVA_API_KEY" \
  --data-urlencode 'query=select * from timeseries' \
  --data-urlencode 'tstype=groupBy' \
  --data-urlencode 'granularity=60000' \
  --data-urlencode "tsparams=$(jq -c '.tsparams' rawber-request.json)"

Prefer POST for nested or large requests. Both transports return finite JSON responses.

For job-based measurement scope, POST /minerva/api/v1/job accepts {"jobId":"12345","subscriberName":"tenant-01"}.

jobId is required. Without subscriberName, the lookup selects the first matching job identifier, so verify the returned subscriber.

Use the returned devices and a verified job interval to scope the measurement query. This lookup does not itself return historical measurements.

Limits and Errors

Use UTC intervals with inclusive starts and exclusive ends. Keep device and interface filters explicit, and apply the required tenant scope.

A result at its limit can be incomplete. Divide large requests into smaller intervals or disjoint device groups.

The count aggregation counts stored rows. It does not necessarily count original samples, unique detections, or incident members.

Preserve stable identities and deduplicate records when extraction windows overlap. Full anomaly queries do not provide a next-page cursor.

Observation

Action

HTTP 401, 403, redirect, or a login page

Verify the API key, authorization, and hostname.

HTTP 404

Verify the endpoint and installation version.

HTTP error, non-JSON body, or application error

Treat the request as failed. Preserve its scope for diagnosis.

Empty or null entries

Check filters, retention, ingestion, and backend health.

Missing dimensions or measures

Verify the datasource and field definitions.

Fewer detail records than expected

Check retained details and missing identities.

An empty result does not establish that no measurements or detections exist. Retention and collection coverage depend on the installation.

Python Examples

For further examples, see the scripts included in the reference configuration package under minerva-configs/rest-api-examples/.

Script

Purpose

query_rawber.py

Retrieve per-minute RawBER maxima for one Cumulus interface

query_anomalies.py

Retrieve rare-syslog detections or other anomaly details

Use Python 3.10 or later. The scripts require no additional Python packages.

Run these examples from that directory. Set MINERVA_BASE and MINERVA_API_KEY as described above.

Bash
python3 query_rawber.py \
  --device leaf-01 --interface swp1 \
  --start 2026-10-29T12:00:00Z --end 2026-10-29T13:00:00Z \
  --bucket-seconds 60 --limit 1000 --output-dir output/rawber

python3 query_anomalies.py \
  --kind rare-syslogs --device leaf-01 \
  --start 2026-10-29T12:00:00Z --end 2026-10-29T13:00:00Z \
  --limit 100 --output-dir output/rare-syslogs

python3 query_anomalies.py \
  --kind anomalies --device leaf-01 \
  --start 2026-10-29T12:00:00Z --end 2026-10-29T13:00:00Z \
  --limit 100 --output-dir output/anomalies

Each script saves the request, response, and CSV results. Add --dry-run to inspect a request without credentials or a network call.

Last updated: