NetQuirk Monitoring API

The NetQuirk Monitoring REST API lets you manage monitors and retrieve metrics programmatically. All responses are JSON.

v1 https://mon.netquirk.com/api/v1

Introduction

The API uses standard HTTP methods and returns JSON responses with consistent error objects. All timestamps are ISO 8601 in UTC.

Base URL: https://mon.netquirk.com/api/v1

Authentication

All /api/v1/monitors* endpoints require an API key. Keys are created via the Create key endpoint (which itself requires your OIDC session token, obtainable from GET /api/auth/me).

Sending your key

Either header works:

Authorization: Bearer nq_<your-key>
X-API-Key: nq_<your-key>

Key management endpoints

GET/POST/DELETE /api/v1/keys require your OIDC Bearer token (the JWT obtained after completing the web login flow).

Errors

All errors return a JSON body with error (machine code) and message (human description).

{
  "error": "not_found",
  "message": "Not found"
}
HTTP Statuserror codeMeaning
400bad_requestInvalid request body or parameters
401unauthorizedMissing, invalid, or expired API key
404not_foundResource does not exist or is not owned by you
409conflictConcurrent operation in progress
500internal_errorUnexpected server error

Pagination

List endpoints return a pagination object alongside the data array.

{
  "monitors": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "total_pages": 3
  }
}

Use ?page=2&limit=50 query params to navigate. Max limit is 100 for monitors and 500 for results.

API Keys

These endpoints use your OIDC Bearer token (not an API key).

GET /api/v1/keys

List all active API keys for your account.

Response 200

{
  "keys": [
    {
      "id": "018e5a1b-...",
      "name": "Production",
      "scopes": [],
      "last_used_at": "2026-04-09T12:34:56Z",
      "expires_at": null,
      "created_at": "2026-04-01T10:00:00Z"
    }
  ]
}
POST /api/v1/keys

Create a new API key. The raw key is returned once — store it securely.

Request body

FieldTypeRequiredDescription
namestringyesHuman-readable label
scopesstring[]noReserved for future use. Pass [] for full access.
expires_atISO 8601noOptional expiry timestamp
POST /api/v1/keys
Authorization: Bearer <oidc-token>

{
  "name": "CI/CD pipeline",
  "scopes": []
}

Response 201

{
  "id": "018e5a1b-...",
  "name": "CI/CD pipeline",
  "key": "nq_4f3a8b...",    // shown once — save this
  "scopes": [],
  "expires_at": null,
  "created_at": "2026-04-09T12:00:00Z"
}
DELETE /api/v1/keys/:id

Permanently revoke an API key. Requests using this key will immediately return 401.

Response 204 No Content

Monitors

GET /api/v1/monitors

List all monitors for your account.

Query params

ParamTypeDefaultDescription
pageinteger1Page number (1-based)
limitinteger20Results per page (1–100)
monitor_typestring—Filter: icmp tcp udp http metrics
enabledboolean—Filter by enabled state
GET /api/v1/monitors?monitor_type=http&enabled=true&limit=50
X-API-Key: nq_...

Response 200

{
  "monitors": [
    {
      "id": "018e5a1b-...",
      "name": "My Website",
      "monitor_type": "http",
      "target": "https://example.com",
      "config": { "type": "http", "method": "GET", "expected_status": 200, ... },
      "check_interval_seconds": 60,
      "timeout_seconds": 30,
      "enabled": true,
      "locations": ["us-east", "eu-west"],
      "created_at": "2026-04-01T10:00:00Z",
      "updated_at": "2026-04-01T10:00:00Z"
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 1, "total_pages": 1 }
}
POST /api/v1/monitors

Create a new monitor.

Common fields

FieldTypeRequiredDescription
namestringyesDisplay name
monitor_typestringyesicmp tcp udp http metrics
targetstringyesHost, URL, or identifier
configobjectyesType-specific config (see below)
descriptionstringnoOptional notes
check_interval_secondsintegernoDefault 60, min 10
timeout_secondsintegernoDefault 30
locationsstring[]nous-east eu-west ap-south
enabledbooleannoDefault true

Config schemas by type

HTTP
{
  "type": "http",
  "method": "GET",                  // GET POST PUT etc.
  "expected_status": 200,
  "verify_ssl": true,
  "follow_redirects": true,
  "max_redirects": 5,
  "headers": { "X-Custom": "val" }, // optional
  "body": null,                     // optional request body
  "response_validation": null       // optional response-body assertion, one of:
                                    //   { "type": "contains",  "pattern": "OK" }
                                    //   { "type": "json_path", "pattern": "$.data.status",
                                    //     "expected_value": "ok" }
                                    //   The json_path subset is a dot path with an
                                    //   optional leading `$`; `expected_value` is
                                    //   compared against the looked-up value.
}
ICMP (ping)
{
  "type": "icmp",
  "packet_size": 64,
  "count": 3
}
TCP
{
  "type": "tcp",
  "port": 443,
  "expect_open": true
}
UDP
{
  "type": "udp",
  "port": 53,
  "send_data": null,       // optional hex or base64 payload
  "expect_response": null  // optional string to match
}
Metrics (agent push)
{
  "type": "metrics",
  "expected_interval_seconds": 60,
  "accept_unknown_metrics": true,
  "metrics": [
    { "key": "cpu_user", "unit": "%", "required": true, "warn_above": 80, "critical_above": 95 }
  ],
  "display_metric": "cpu_user",
  "display_mode": "auto_worst"
}

Example: HTTP monitor

POST /api/v1/monitors
X-API-Key: nq_...

{
  "name": "API health check",
  "monitor_type": "http",
  "target": "https://api.example.com/health",
  "config": {
    "type": "http",
    "method": "GET",
    "expected_status": 200,
    "verify_ssl": true,
    "follow_redirects": false,
    "max_redirects": 5
  },
  "check_interval_seconds": 60,
  "locations": ["us-east", "eu-west"]
}

Response 201

Returns the created Monitor object.

GET /api/v1/monitors/:id

Retrieve a single monitor by UUID.

Response 200

Returns the Monitor object.

PUT /api/v1/monitors/:id

Update a monitor. All fields are optional — omitted fields keep their current value.

PUT /api/v1/monitors/018e5a1b-...
X-API-Key: nq_...

{
  "enabled": false,
  "check_interval_seconds": 120
}

Response 200

Returns the updated Monitor object.

DELETE /api/v1/monitors/:id

Permanently delete a monitor and all associated data.

Response 204 No Content

Monitor Data

GET /api/v1/monitors/:id/status

Current up/down status across all check locations.

Response 200

{
  "monitor_id": "018e5a1b-...",
  "status": "up",                       // "up" | "down" | "stale" | "disabled" | "unknown"
  "last_checked_at": "2026-04-09T14:59:00Z",
  "last_success_at": "2026-04-09T14:59:00Z",
  "response_time_ms": 142,
  "message": null,
  "locations": [
    {
      "location": "us-east",
      "status": "up",
      "last_checked_at": "2026-04-09T14:59:00Z",
      "response_time_ms": 142,
      "message": null
    },
    {
      "location": "eu-west",
      "status": "up",
      "last_checked_at": "2026-04-09T14:58:57Z",
      "response_time_ms": 89,
      "message": null
    }
  ]
}
GET /api/v1/monitors/:id/results

Historical check results (not available for metrics-type monitors).

Query params

ParamTypeDefaultDescription
pageinteger1Page number
limitinteger50Results per page (1–500)
sinceISO 8601—Only return results after this timestamp
locationstring—Filter to a single check location
GET /api/v1/monitors/018e5a1b-.../results?since=2026-04-08T00:00:00Z&location=us-east
X-API-Key: nq_...

Response 200

{
  "results": [
    {
      "checked_at": "2026-04-09T15:00:00Z",
      "location": "us-east",
      "success": true,
      "response_time_ms": 142,
      "status_code": 200,
      "error_message": null
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 1440, "total_pages": 29 }
}
GET /api/v1/monitors/:id/metrics

List all available metric keys for a monitor and their most recent values. Useful for discovering what metrics are being pushed by an agent.

Response 200

{
  "metrics": [
    { "key": "cpu_user",   "value": 1234,  "last_updated_at": "2026-04-09T15:00:00Z" },
    { "key": "cpu_system", "value": 456,   "last_updated_at": "2026-04-09T15:00:00Z" },
    { "key": "ram_used",   "value": 87432, "last_updated_at": "2026-04-09T15:00:00Z" }
  ]
}

Values are raw internal units scaled ×100 for percentage metrics (e.g. cpu_user: 1234 = 12.34%).

GET /api/v1/monitors/:id/metrics/:key

Time-series data for a single metric key. Use this to draw graphs.

Query params

ParamTypeDefaultDescription
fromISO 8601—Range start (use with to)
toISO 8601—Range end
limitinteger1000Max points (1–10 000)
GET /api/v1/monitors/018e5a1b-.../metrics/cpu_user?from=2026-04-08T00:00:00Z&to=2026-04-09T00:00:00Z
X-API-Key: nq_...

Response 200

{
  "monitor_id": "018e5a1b-...",
  "metric": "cpu_user",
  "points": [
    { "timestamp": "2026-04-08T00:00:00Z", "value": 1024 },
    { "timestamp": "2026-04-08T00:01:00Z", "value": 1156 },
    ...
  ]
}

Points are returned in chronological order. If neither from/to nor limit is provided, the most recent 1 000 samples are returned.

Common metric keys

KeyUnitDescription
cpu_user% ×100User-space CPU usage
cpu_system% ×100Kernel CPU usage
cpu_iowait% ×100I/O wait CPU
ram_used% ×100RAM used
ram_free% ×100RAM free
loadavg×1001-minute load average
disk_used:{path}% ×100Disk used for a path
net_rx:{iface}bytes/sNetwork receive rate
net_tx:{iface}bytes/sNetwork transmit rate
GET /api/v1/monitors/flapping

Fleet-wide count of up/down transitions per monitor for a chosen window, plus the monitor with the most. Use this to spot monitors that flap (alternate success and failure rapidly) rather than fail cleanly.

Query params

ParamTypeDefaultDescription
windowstring24h Window length: <n>h or <n>d (e.g. 24h, 7d).
GET /api/v1/monitors/flapping?window=24h
X-API-Key: nq_...

Response 200

{
  "window": "24h",
  "window_seconds": 86400,
  "monitors": [
    { "monitor_id": "018e5a1b-...", "name": "Login API", "transitions": 12 },
    { "monitor_id": "018e5a1c-...", "name": "Static CDN", "transitions": 0 }
  ],
  "top": { "monitor_id": "018e5a1b-...", "name": "Login API", "transitions": 12 }
}

A transition is an adjacent pair of stored checks whose success flag differs (up→down, down→up, …). top is null when the caller owns no monitors. The count is bounded by the same per-monitor limit that powers /uptime; very high-frequency monitors over a long window may under-count transitions at the bound.

The Monitor object

{
  "id": "018e5a1b-2c3d-7e4f-a5b6-c7d8e9f01234",  // UUID
  "name": "My Website",
  "description": null,                              // string | null
  "monitor_type": "http",                           // icmp | tcp | udp | http | metrics
  "target": "https://example.com",
  "config": { ... },                               // type-specific config object
  "check_interval_seconds": 60,
  "timeout_seconds": 30,
  "enabled": true,
  "locations": ["us-east", "eu-west"],             // empty for metrics type
  "created_at": "2026-04-01T10:00:00Z",
  "updated_at": "2026-04-09T15:00:00Z"
}

Quick start

Create an HTTP monitor and check its status in three curl commands.

# 1. Get your OIDC token (after web login)
TOKEN=$(curl -s https://mon.netquirk.com/api/auth/me \
  -H "Authorization: Bearer <session-jwt>" | jq -r .token)

# 2. Create an API key
KEY=$(curl -s -X POST https://mon.netquirk.com/api/v1/keys \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"quickstart"}' | jq -r .key)

# 3. Create a monitor
ID=$(curl -s -X POST https://mon.netquirk.com/api/v1/monitors \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Example",
    "monitor_type": "http",
    "target": "https://example.com",
    "config": {"type":"http","method":"GET","expected_status":200,"verify_ssl":true,"follow_redirects":true,"max_redirects":5},
    "locations": ["us-east"]
  }' | jq -r .id)

# 4. Check status
curl -s "https://mon.netquirk.com/api/v1/monitors/$ID/status" \
  -H "X-API-Key: $KEY" | jq .