Skip to content

Latest commit

 

History

History
1266 lines (950 loc) · 21.9 KB

File metadata and controls

1266 lines (950 loc) · 21.9 KB

NetWatcher API Reference

Base URL

https://api.netwatcher.io

Authentication

User Authentication (JWT)

All protected routes require a valid JWT token in the Authorization header:

Authorization: Bearer <jwt_token>

Agent Authentication (PSK/PIN)

Agents authenticate via:

  • PIN – One-time bootstrap credential
  • PSK – Persistent pre-shared key (returned after PIN bootstrap)

Response Format

List Endpoints

All list endpoints return data wrapped in a consistent format:

{
  "data": [ /* array of items */ ],
  "total": 100,    // optional: total count (for paginated endpoints)
  "limit": 50,     // optional: requested limit
  "offset": 0      // optional: requested offset
}

Single Item Endpoints

Single item endpoints return the object directly:

{
  "id": 1,
  "name": "Example",
  // ... other fields
}

Error Responses

All errors return:

{
  "error": "error message here"
}

Auth Endpoints

POST /auth/register

Register a new user account.

Request Body:

{
  "email": "user@example.com",
  "password": "securepassword",
  "name": "John Doe",
  "role": "USER",
  "labels": {},
  "metadata": {}
}

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "data": {
    "id": 1,
    "email": "user@example.com",
    "name": "John Doe",
    "role": "USER",
    "verified": false,
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-01T00:00:00Z"
  }
}

POST /auth/login

Authenticate an existing user.

Request Body:

{
  "email": "user@example.com",
  "password": "securepassword"
}

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "data": { /* User object */ }
}

Agent Endpoints

POST /agent

Agent login/bootstrap endpoint. Supports both PIN bootstrap and PSK authentication.

Request Body (PIN Bootstrap):

{
  "workspace_id": 1,
  "agent_id": 10,
  "pin": "123456789"
}

Response (Bootstrap Success):

{
  "status": "success",
  "psk": "generated-psk-token",
  "agent": { /* Agent object */ }
}

Request Body (PSK Auth):

{
  "workspace_id": 1,
  "agent_id": 10,
  "psk": "existing-psk-token"
}

Response (PSK Success):

{
  "status": "ok",
  "agent": { /* Agent object */ }
}

Agent API Endpoints

Agent-specific API endpoints authenticated via PSK headers. These allow agents to access controller services without JWT.

Required Headers:

X-Workspace-ID: <workspace_id>
X-Agent-ID: <agent_id>
X-Agent-PSK: <psk_token>

GET /agent/api/whoami

Returns the agent's public IP as seen by the controller. Useful for agents to discover their public IP without external services.

Query Parameters:

Param Type Default Description
quick bool false If true, returns only IP without GeoIP enrichment

Response (Full):

{
  "ip": "203.0.113.45",
  "geoip": {
    "city": { "name": "Vancouver", "subdivision": "BC" },
    "country": { "code": "CA", "name": "Canada" },
    "asn": { "number": 852, "organization": "TELUS Communications" },
    "coordinates": { "latitude": 49.2827, "longitude": -123.1207 }
  },
  "reverse_dns": "host-203-0-113-45.example.com",
  "timestamp": "2026-01-23T17:30:00Z"
}

Response (Quick):

{
  "ip": "203.0.113.45",
  "timestamp": "2026-01-23T17:30:00Z"
}

GET /agent/api/lookup/ip/{ip}

IP intelligence lookup for agents. Returns GeoIP + ASN + reverse DNS for any IP.

Response:

{
  "ip": "8.8.8.8",
  "geoip": {
    "country": { "code": "US", "name": "United States" },
    "asn": { "number": 15169, "organization": "GOOGLE" }
  },
  "reverse_dns": "dns.google",
  "timestamp": "2026-01-23T17:30:00Z"
}

Workspace Endpoints

GET /workspaces

List all workspaces for the authenticated user.

Query Parameters:

Param Type Default Description
q string - Search query
limit int 50 Max results (1-200)
offset int 0 Pagination offset

Response:

{
  "data": [
    {
      "id": 1,
      "name": "Production",
      "ownerId": 1,
      "description": "Production network monitoring",
      "settings": {},
      "createdAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}

POST /workspaces

Create a new workspace.

Request Body:

{
  "name": "My Workspace",
  "description": "Optional description",
  "settings": {}
}

GET /workspaces/{id}

Get a specific workspace by ID.

Required Role: Any workspace member

Response includes user's role:

{
  "id": 1,
  "name": "Production",
  "description": "...",
  "my_role": "ADMIN"
}

PATCH /workspaces/{id}

Update workspace properties.

Required Role: ADMIN

Request Body:

{
  "name": "new-name",
  "description": "Updated description",
  "settings": { "key": "value" }
}

DELETE /workspaces/{id}

Delete a workspace (soft delete).

Required Role: OWNER


Workspace Member Endpoints

GET /workspaces/{id}/members

List all members of a workspace.

Required Role: Any workspace member


POST /workspaces/{id}/members

Invite a new member to the workspace.

Required Role: ADMIN

Request Body:

{
  "userId": 0,
  "email": "newuser@example.com",
  "role": "USER",
  "meta": {}
}

Roles: USER, ADMIN, OWNER


PATCH /workspaces/{id}/members/{memberId}

Update a member's role.

Required Role: ADMIN

Request Body:

{
  "role": "ADMIN"
}

DELETE /workspaces/{id}/members/{memberId}

Remove a member from the workspace.

Required Role: ADMIN


POST /workspaces/{id}/accept-invite

Accept a pending workspace invitation.

Request Body:

{
  "email": "user@example.com"
}

POST /workspaces/{id}/transfer-ownership

Transfer workspace ownership to another user.

Required Role: OWNER

Request Body:

{
  "newOwnerUserId": 5
}

Agent Management Endpoints

GET /workspaces/{id}/agents

List all agents in a workspace.

Required Role: Any workspace member

Query Parameters:

Param Type Default Description
limit int 50 Max results (1-200)
offset int 0 Pagination offset

Response:

{
  "data": [
    {
      "id": 10,
      "workspace_id": 1,
      "name": "Office Router",
      "description": "Main office network monitor",
      "location": "Vancouver, BC",
      "public_ip_override": "",
      "version": "1.2.0",
      "last_seen_at": "2024-01-01T12:00:00Z",
      "initialized": true,
      "labels": {},
      "metadata": {}
    }
  ],
  "total": 1
}

POST /workspaces/{id}/agents

Create a new agent with bootstrap PIN.

Required Role: USER

Request Body:

{
  "name": "New Agent",
  "description": "Description here",
  "location": "Seattle, WA",
  "public_ip_override": "",
  "version": "",
  "pinLength": 9,
  "pinTTLSeconds": 3600,
  "labels": {},
  "metadata": {}
}

Response:

{
  "agent": { /* Agent object */ },
  "pin": "123456789"
}

GET /workspaces/{id}/agents/{agentID}

Get a specific agent.

Required Role: Any workspace member


PATCH /workspaces/{id}/agents/{agentID}

Update agent properties.

Required Role: USER

Request Body:

{
  "name": "Updated Name",
  "description": "Updated description",
  "location": "New Location",
  "labels": { "env": "production" }
}

DELETE /workspaces/{id}/agents/{agentID}

Delete an agent.

Required Role: ADMIN


POST /workspaces/{id}/agents/{agentID}/heartbeat

Manual heartbeat update.

Response:

{
  "ok": true,
  "ts": "2024-01-01T12:00:00Z"
}

POST /workspaces/{id}/agents/{agentID}/issue-pin

Issue a new bootstrap PIN for an agent.

Request Body:

{
  "pinLength": 9,
  "ttlSeconds": 3600
}

Response:

{
  "pin": "987654321"
}

GET /workspaces/{id}/agents/{agentID}/netinfo

Get the latest network info for an agent.


GET /workspaces/{id}/agents/{agentID}/sysinfo

Get the latest system info for an agent.


Probe Endpoints

GET /workspaces/{id}/agents/{agentID}/probes

List all probes for an agent.


POST /workspaces/{id}/agents/{agentID}/probes

Create a new probe.

Request Body:

{
  "workspace_id": 1,
  "agent_id": 10,
  "type": "PING",
  "enabled": true,
  "interval_sec": 60,
  "timeout_sec": 10,
  "count": 5,
  "duration_sec": 0,
  "server": false,
  "targets": ["8.8.8.8", "1.1.1.1"],
  "agent_targets": [],
  "labels": {},
  "metadata": {}
}

Probe Types:

Type Description
MTR Traceroute with per-hop stats
PING ICMP ping
SPEEDTEST Speed test
SYSINFO System information
NETINFO Network information
TRAFFICSIM Traffic simulation

GET /workspaces/{id}/agents/{agentID}/probes/{probeID}

Get a specific probe.


PATCH /workspaces/{id}/agents/{agentID}/probes/{probeID}

Update probe settings.

Request Body:

{
  "enabled": false,
  "intervalSec": 120,
  "timeoutSec": 15,
  "labels": { "priority": "high" },
  "replaceTargets": ["8.8.4.4"]
}

DELETE /workspaces/{id}/agents/{agentID}/probes/{probeID}

Delete a probe.


Probe Data Endpoints

GET /workspaces/{id}/probe-data/find

Flexible query across all probe data.

Query Parameters:

Param Type Description
type string Filter by probe type (PING, MTR, etc.)
probeId uint Filter by specific probe
agentId uint Filter by reporting agent
probeAgentId uint Filter by probe-owning agent
targetAgent uint Filter by target agent
targetPrefix string Filter by target prefix
triggered bool Filter by triggered status
from time Start timestamp (RFC3339 or Unix)
to time End timestamp
limit int Max results
asc bool Sort ascending (default: false)

GET /workspaces/{id}/probe-data/probes/{probeID}/data

Get time-series data for a specific probe.

Query Parameters:

Param Type Default Description
from time - Start timestamp
to time - End timestamp
limit int 0 Max results
asc bool false Sort ascending

GET /workspaces/{id}/probe-data/latest

Get the latest probe data by type and agent.

Query Parameters:

Param Type Required Description
type string Yes Probe type
agentId uint Yes Agent ID
probeId uint No Specific probe ID

GET /workspaces/{id}/probe-data/by-target/data

Get probe data for a specific target.

Query Parameters:

Param Type Required Description
target string Yes Target host/IP
type string No Filter by probe type
from time No Start timestamp
to time No End timestamp
limit int No Max results
latestOnly bool No Return only latest

GET /workspaces/{id}/probe-data/probes/{probeID}/similar

Find similar probes (same targets or target agents).

Query Parameters:

Param Type Default Description
sameType bool true Restrict to same probe type
includeSelf bool false Include the reference probe
latest bool false Include latest data points

WebSocket API

Connection

ws://api.netwatcher.io/ws

Required Headers:

X-Workspace-ID: <workspace_id>
X-Agent-ID: <agent_id>
X-Agent-PSK: <psk_token>

Events (Agent Namespace)

Event Direction Description
probe_get Agent → Controller Request probe configurations
probe_get Controller → Agent Probe config response
probe_post Agent → Controller Submit probe results
probe_post_ok Controller → Agent Acknowledgment
version Agent → Controller Report agent version
version Controller → Agent Acknowledgment

probe_post Payload

{
  "probe_id": 123,
  "triggered": false,
  "triggered_reason": "",
  "created_at": "2024-01-01T12:00:00Z",
  "type": "PING",
  "payload": { /* type-specific data */ },
  "target": "8.8.8.8",
  "target_agent": 0

Panel WebSocket API

Real-time updates for panel clients.

Connection

ws://api.netwatcher.io/ws/panel

Required Headers:

Authorization: Bearer <jwt_token>

Message Types

Subscribe

Subscribe to probe data updates for a workspace:

{
  "type": "subscribe",
  "workspace_id": 1,
  "probe_id": 0
}

Set probe_id to 0 to receive all probe updates for the workspace.

probe_data (Server → Client)

Real-time probe data broadcast:

{
  "type": "probe_data",
  "workspace_id": 1,
  "probe_id": 123,
  "agent_id": 10,
  "probe_type": "PING",
  "data": { /* probe result */ }
}

speedtest_update (Server → Client)

Speedtest queue status changes:

{
  "type": "speedtest_update",
  "workspace_id": 1,
  "agent_id": 10,
  "queue_id": 456,
  "status": "running"
}

network_map_update (Server → Client)

Network topology changes:

{
  "type": "network_map_update",
  "workspace_id": 1,
  "nodes": [...],
  "edges": [...],
  "generated_at": "2024-01-01T12:00:00Z"
}

GeoIP Endpoints

IP geolocation and ASN lookup using MaxMind GeoLite2 databases.

Note: These endpoints require GeoIP databases to be configured. Check /geoip/status for availability.

GET /geoip/lookup

Look up geographic and ASN information for a single IP address.

Query Parameters:

Param Type Required Description
ip string Yes IP address to look up

Response:

{
  "ip": "8.8.8.8",
  "city": {
    "name": "Mountain View",
    "subdivision": "CA"
  },
  "country": {
    "code": "US",
    "name": "United States"
  },
  "asn": {
    "number": 15169,
    "organization": "GOOGLE"
  },
  "coordinates": {
    "latitude": 37.4056,
    "longitude": -122.0775,
    "accuracy_radius": 1000
  }
}

POST /geoip/lookup

Bulk IP lookup (maximum 100 IPs per request).

Request Body:

{
  "ips": ["8.8.8.8", "1.1.1.1", "208.67.222.222"]
}

Response:

{
  "data": [
    { "ip": "8.8.8.8", "city": {...}, "country": {...}, "asn": {...} },
    { "ip": "1.1.1.1", "country": {...}, "asn": {...} }
  ],
  "total": 2
}

GET /geoip/status

Check which GeoIP databases are loaded.

Response:

{
  "city": true,
  "country": true,
  "asn": true
}

OUI Lookup Endpoints

MAC address vendor (OUI) lookup using the IEEE database.

GET /lookup/oui/{mac}

Look up the vendor for a MAC address.

Path Parameters:

Param Type Required Description
mac string Yes MAC address (any format)

Supported MAC Formats:

  • 00:1C:42:XX:XX:XX
  • 00-1C-42-XX-XX-XX
  • 001C42XXXXXX

Response:

{
  "mac": "00:1C:42:AB:CD:EF",
  "oui": "00-1C-42",
  "vendor": "Parallels, Inc.",
  "found": true
}

POST /lookup/oui

Bulk MAC vendor lookup (maximum 100 per request).

Request Body:

{
  "macs": ["00:1C:42:AB:CD:EF", "00:00:5E:00:01:01"]
}

Response:

{
  "results": [
    { "mac": "00:1C:42:AB:CD:EF", "oui": "00-1C-42", "vendor": "Parallels, Inc.", "found": true },
    { "mac": "00:00:5E:00:01:01", "oui": "00-00-5E", "vendor": "ICANN, IANA Department", "found": true }
  ],
  "count": 2
}

GET /lookup/oui/status

Check if the OUI database is loaded.

Response:

{
  "loaded": true,
  "entry_count": 35000
}

WHOIS Endpoints

WHOIS lookup for IP addresses and domain names.

GET /whois/lookup

Perform a WHOIS query for an IP address or domain name.

Query Parameters:

Param Type Required Description
query string Yes IP address or domain name
ip string No Alternative to query for IP lookups

Input Validation:

  • IP addresses are validated with net.ParseIP()
  • Domain names are validated against a strict regex pattern
  • Invalid input returns 400 error before any command execution

Response:

{
  "query": "8.8.8.8",
  "raw_output": "NetRange: 8.8.8.0 - 8.8.8.255\nCIDR: 8.8.8.0/24\n...",
  "parsed": {
    "netname": "LVLT-GOGL-8-8-8",
    "netrange": "8.8.8.0 - 8.8.8.255",
    "organization": "Google LLC",
    "country": "US"
  },
  "lookup_time_ms": 450
}

Parsed Fields:

Field Description
netname Network name
netrange IP range (CIDR or range format)
organization Organization name
country Country code
registrar Domain registrar
created Creation date
updated Last update date
abuse_email Abuse contact email

Lookup Endpoints

Combined IP lookup service providing both GeoIP and WHOIS data in a single request.

GET /lookup/combined

Combined GeoIP and WHOIS lookup. Accepts both IP addresses and hostnames.

Query Parameters:

Param Type Required Description
ip string Yes IP address or hostname to look up

Response:

{
  "ip": "8.8.8.8",
  "hostname": "dns.google",
  "geoip": {
    "ip": "8.8.8.8",
    "city": { "name": "Mountain View", "subdivision": "CA" },
    "country": { "code": "US", "name": "United States" },
    "asn": { "number": 15169, "organization": "GOOGLE" },
    "coordinates": { "latitude": 37.4056, "longitude": -122.0775 },
    "cached": true,
    "cache_time": "2024-01-01T12:00:00Z"
  },
  "whois": {
    "query": "8.8.8.8",
    "raw_output": "...",
    "parsed": { "netname": "LVLT-GOGL-8-8-8", "organization": "Google LLC" },
    "cached": true,
    "cache_time": "2024-01-01T12:00:00Z"
  },
  "cached": true,
  "cache_time": "2024-01-01T12:00:00Z"
}

Notes:

  • If the input is a hostname, it is resolved to an IP address first
  • The hostname field is included only when a hostname was provided
  • Both GeoIP and WHOIS lookups are cached in ClickHouse
  • Errors for individual lookups are returned in an errors object

Alert Endpoints

GET /workspaces/alerts

List alerts across all workspaces the user has access to.

Query Parameters:

Param Type Default Description
status string - Filter by status: active, acknowledged, resolved
limit int 50 Max results

Response:

{
  "data": [
    {
      "id": 123,
      "workspace_id": 1,
      "probe_id": 45,
      "agent_id": 10,
      "probe_type": "PING",
      "probe_name": "Core Router",
      "probe_target": "10.0.0.1",
      "agent_name": "Edge-Node-01",
      "metric": "packet_loss",
      "value": 5.2,
      "threshold": 1.0,
      "severity": "critical",
      "status": "active",
      "triggered_at": "2026-01-12T20:30:00Z"
    }
  ]
}

GET /workspaces/alerts/count

Get count of active alerts across all workspaces.

Response:

{
  "count": 5
}

PATCH /alerts/{id}

Update alert status (acknowledge or resolve).

Request Body:

{
  "status": "acknowledged"
}

GET /workspaces/{id}/alert-rules

List alert rules for a workspace.

Required Role: Any workspace member


POST /workspaces/{id}/alert-rules

Create a new alert rule.

Required Role: ADMIN

Request Body:

{
  "name": "High Packet Loss",
  "metric": "packet_loss",
  "operator": ">",
  "threshold": 5.0,
  "severity": "critical",
  "notify_panel": true,
  "notify_webhook": true,
  "webhook_url": "https://hooks.example.com/alert",
  "webhook_secret": "optional-hmac-secret",
  "probe_id": null,
  "agent_id": null,
  "enabled": true
}

PATCH /workspaces/{id}/alert-rules/{ruleId}

Update an alert rule.

Required Role: ADMIN


DELETE /workspaces/{id}/alert-rules/{ruleId}

Delete an alert rule.

Required Role: ADMIN


Probe Copy Endpoint

POST /workspaces/{id}/agents/{agentID}/probes/copy

Copy probes from one agent to multiple destination agents.

Required Role: USER

Request Body:

{
  "source_agent_id": 10,
  "dest_agent_ids": [11, 12, 13],
  "workspace_id": 1,
  "probe_ids": [],
  "probe_types": ["AGENT", "MTR"],
  "match_targets": false,
  "skip_duplicates": true
}

Response:

{
  "created": 6,
  "skipped": 2,
  "errors": 0,
  "results": [
    {
      "source_probe_id": 100,
      "dest_agent_id": 11,
      "new_probe_id": 150
    },
    {
      "source_probe_id": 101,
      "dest_agent_id": 11,
      "skipped": true,
      "skip_reason": "duplicate exists"
    }
  ]
}

Options:

Field Description
probe_ids Specific probes to copy (empty = all)
probe_types Filter by type (AGENT, MTR, PING, etc.)
match_targets Only copy probes targeting dest agents
skip_duplicates Skip if probe already exists on dest

Bidirectional Probes

When creating AGENT probes, set bidirectional: true to automatically create reciprocal probes:

Request Body:

{
  "type": "AGENT",
  "agent_targets": [20],
  "bidirectional": true
}

This creates:

  • Primary probe: Agent A → Agent B
  • Reverse probe: Agent B → Agent A

Both probes are created atomically within a single transaction.


Health Check

GET /healthz

Returns service health status.

Response:

{
  "ok": true
}