The TowerOps GraphQL API provides a flexible, strongly-typed interface for querying and managing your network infrastructure. Request exactly the data you need in a single request — no over-fetching, no under-fetching.
The GraphQL API uses the same authentication as the <.link navigate={~p"/docs/api"} class="text-cerulean-600 hover:text-cerulean-500 dark:text-cerulean-400" > REST API and provides equivalent functionality with the added benefit of nested queries and precise field selection.
Prefer infrastructure-as-code? The Towerops Ansible collection covers every resource exposed here: codeberg.org/towerops/ansible.
Authenticate using a Bearer token in the
Authorization
header.
API tokens can be created in your organization settings.
Authorization: Bearer <%= @sample_token %>
All GraphQL requests are sent as
POST
to a single endpoint:
POST https://app.towerops.net/api/graphql
Send a JSON body with a
query
field
and optional variables:
curl -X POST https://app.towerops.net/api/graphql \
-H "Authorization: Bearer <%= @sample_token %>" \
-H "Content-Type: application/json" \
<%= raw(~S|-d '{"query": "{ devices { id name ipAddress status } }"}'|) %>
List all devices. Optionally filter by site or status.
| Argument | Type | Description |
|---|---|---|
| siteId | ID | Filter by site |
| status | String | Filter by status (up, down, unknown) |
| limit | Int | Max results (default: 100) |
<%= raw(~S[{
devices(siteId: "uuid", status: "up") {
id
name
ipAddress
status
lastCheckedAt
monitoringEnabled
snmpEnabled
deviceRole
site {
id
name
location
}
}
}]) %>
Get a single device by ID.
<%= raw(~S[{
device(id: "device-uuid") {
id
name
ipAddress
status
description
snmpVersion
snmpPort
checkIntervalSeconds
site { id name }
}
}]) %>
List all sites for the organization.
<%= raw(~S[{
sites {
id
name
description
location
snmpVersion
snmpCommunity
insertedAt
}
}]) %>
Get a single site by ID.
<%= raw(~S[{ site(id: "site-uuid") { id name location } }]) %>
List alerts. Filter by status or device.
| Argument | Type | Description |
|---|---|---|
| status | String | active, acknowledged, or resolved |
| deviceId | ID | Filter by device |
| limit | Int | Max results (default: 100) |
<%= raw(~S[{
alerts(status: "active", limit: 10) {
id
alertType
message
triggeredAt
acknowledgedAt
resolvedAt
deviceId
device {
id
name
ipAddress
}
acknowledgedByEmail
}
}]) %>
<%= raw(~S[{
agents {
id
name
enabled
lastSeenAt
lastIp
isCloudPoller
deviceCount
metadata
}
}
# Single agent
{ agent(id: "agent-uuid") { id name enabled deviceCount } }]) %>
<%= raw(~S[{
organization {
id
name
slug
subscriptionPlan
useSites
snmpVersion
snmpCommunity
snmpPort
snmpTransport
mikrotikEnabled
mikrotikUsername
mikrotikPort
mikrotikUseSsl
defaultAgentTokenId
}
}]) %>
<%= raw(~S[{
members {
id
email
role
insertedAt
}
}]) %>
<%= raw(~S[{
integrations {
id
provider
enabled
syncIntervalMinutes
lastSyncedAt
lastSyncStatus
}
}]) %>
<%= raw(~S[{
activity(limit: 20) {
summary
detail
timestamp
severity
deviceName
siteName
link
type
}
}]) %>
Get time-series metrics for a device.
| Argument | Type | Description |
|---|---|---|
| deviceId | ID! | Required device ID |
| sensorType | String | Filter by sensor type |
| timeRange | String | e.g. "24h", "72h" (default: "24h") |
<%= raw(~S[{
deviceMetrics(deviceId: "device-uuid", timeRange: "48h") {
timestamp
value
status
checkName
checkType
}
}]) %>
Get SNMP interfaces for a device.
<%= raw(~S[{
deviceInterfaces(deviceId: "device-uuid") {
id
ifIndex
ifName
ifDescr
ifType
ifSpeed
ifAdminStatus
ifOperStatus
ifAlias
}
}]) %>
Query historical sensor readings, interface traffic rates, and monitoring check results.
All time-series queries support a
timeRange
argument (e.g. "1h", "24h", "72h").
List all SNMP sensors discovered on a device.
| Argument | Type | Description |
|---|---|---|
| deviceId | ID! | Required device ID |
<%= raw(~S[{
deviceSensors(deviceId: "device-uuid") {
id
sensorType
sensorUnit
sensorDescr
currentValue
lastCheckedAt
monitored
}
}]) %>
Get historical readings for a specific sensor.
| Argument | Type | Description |
|---|---|---|
| sensorId | ID! | Required sensor ID |
| timeRange | String | e.g. "1h", "24h", "72h" (default: "24h") |
<%= raw(~S[{
sensorReadings(sensorId: "sensor-uuid", timeRange: "24h") {
sensorId
value
status
checkedAt
}
}]) %>
Get traffic rates (bits per second) computed from SNMP counter deltas for a network interface.
| Argument | Type | Description |
|---|---|---|
| interfaceId | ID! | Required interface ID |
| timeRange | String | e.g. "1h", "24h", "72h" (default: "24h") |
<%= raw(~S[{
interfaceTraffic(interfaceId: "interface-uuid", timeRange: "24h") {
timestamp
inBps
outBps
inErrors
outErrors
}
}]) %>
Get historical results for a monitoring check (ping, HTTP, etc.).
| Argument | Type | Description |
|---|---|---|
| checkId | ID! | Required check ID |
| timeRange | String | e.g. "1h", "24h" (default: "1h") |
<%= raw(~S[{
checkResults(checkId: "check-uuid", timeRange: "1h") {
checkId
value
status
checkedAt
responseTimeMs
}
}]) %>
List and inspect HTTP, TCP, DNS, and ping service checks.
<%= raw(~S[{
checks(checkType: "http", deviceId: "device-uuid") {
id
name
checkType
enabled
intervalSeconds
currentState
config
}
}]) %>
<%= raw(~S[{
check(id: "check-uuid") {
id
name
checkType
config
currentState
currentStateType
lastCheckAt
}
}]) %>
Inspect schedules and find out who is currently on call.
<%= raw(~S[{
schedules {
id
name
timezone
description
}
}]) %>
<%= raw(~S[{
schedule(id: "schedule-uuid") {
id
name
timezone
layers {
id
name
position
rotationType
members {
userId
position
}
}
overrides {
id
userId
startTime
endTime
}
}
}]) %>
<%= raw(~S[{
onCall(scheduleId: "schedule-uuid") {
userId
email
}
}]) %>
Inspect escalation policies and their rules + targets.
<%= raw(~S[{
escalationPolicies {
id
name
description
repeatCount
repeatIntervalMinutes
}
}]) %>
<%= raw(~S[{
escalationPolicy(id: "policy-uuid") {
id
name
rules {
id
position
delayMinutes
targets {
id
targetType
userId
scheduleId
}
}
}
}]) %>
Inspect planned and active maintenance windows. The optional filter
argument accepts active, upcoming, or past.
<%= raw(~S[{
maintenanceWindows(filter: "upcoming") {
id
name
startsAt
endsAt
suppressAlerts
siteId
deviceId
}
}]) %>
<%= raw(~S[mutation {
createDevice(input: {
ipAddress: "192.168.1.1"
name: "Core Router"
siteId: "site-uuid"
snmpEnabled: true
snmpVersion: "2c"
snmpCommunity: "public"
}) {
id
name
ipAddress
status
}
}]) %>
<%= raw(~S[mutation {
updateDevice(id: "device-uuid", input: {
name: "Updated Router"
monitoringEnabled: false
}) {
id
name
monitoringEnabled
}
}]) %>
<%= raw(~S[mutation {
deleteDevice(id: "device-uuid") {
success
message
}
}]) %>
<%= raw(~S[mutation {
createSite(input: {
name: "Main Office"
location: "New York, NY"
snmpCommunity: "public"
}) {
id
name
location
}
}]) %>
Same pattern as device mutations.
<%= raw(~S[mutation {
acknowledgeAlert(id: "alert-uuid") {
id
acknowledgedAt
acknowledgedByEmail
}
}]) %>
<%= raw(~S[mutation {
resolveAlert(id: "alert-uuid") {
id
resolvedAt
}
}]) %>
Creates a new agent token. The raw token is only returned once.
<%= raw(~S[mutation {
createAgent(name: "DC1 Agent") {
id
name
token
}
}]) %>
<%= raw(~S[mutation { deleteAgent(id: "agent-uuid") { success message } }]) %>
<%= raw(~S[mutation {
updateOrganization(input: {
name: "My Network"
useSites: true
snmpVersion: "2c"
snmpCommunity: "public"
mikrotikEnabled: true
mikrotikUsername: "admin"
mikrotikPort: 8729
mikrotikUseSsl: true
}) {
id
name
useSites
snmpVersion
mikrotikEnabled
}
}]) %>
<%= raw(~S[mutation {
sendInvitation(email: "user@example.com", role: "admin") {
id
email
role
expiresAt
}
}]) %>
<%= raw(~S[mutation {
updateMemberRole(id: "user-uuid", role: "admin") {
id
email
role
}
}]) %>
<%= raw(~S[mutation { removeMember(id: "user-uuid") { success message } }
mutation { cancelInvitation(id: "invitation-uuid") { success message } }]) %>
<%= raw(~S[mutation {
createIntegration(input: {
provider: "preseem"
enabled: true
credentials: "{\"api_key\": \"xxx\"}"
syncIntervalMinutes: 10
}) {
id
provider
enabled
}
}]) %>
<%= raw(~S[mutation {
testIntegration(id: "integration-uuid") {
success
message
}
}]) %>
<%= raw(~S[mutation {
createCheck(input: {
name: "API health"
checkType: "http"
deviceId: "device-uuid"
intervalSeconds: 60
config: {url: "https://api.example.com/health", method: "GET"}
}) {
id
name
checkType
}
}]) %>
<%= raw(~S[mutation {
updateCheck(id: "check-uuid", input: {intervalSeconds: 30}) {
id
intervalSeconds
}
}
mutation {
deleteCheck(id: "check-uuid") {
success
}
}]) %>
<%= raw(~S[mutation {
createSchedule(input: {
name: "Primary on-call"
timezone: "America/Chicago"
}) {
id
name
}
}
mutation {
updateSchedule(id: "schedule-uuid", input: {description: "Weekly rotation"}) {
id
description
}
}
mutation {
deleteSchedule(id: "schedule-uuid") {
success
}
}]) %>
<%= raw(~S[mutation {
createLayer(scheduleId: "schedule-uuid", input: {
name: "Primary"
position: 0
rotationType: "weekly"
rotationInterval: 1
handoffTime: "09:00:00"
startDate: "2026-06-01T00:00:00Z"
}) {
id
}
}
mutation {
addLayerMember(layerId: "layer-uuid", userId: "user-uuid", position: 0) {
id
}
}
mutation {
removeLayerMember(id: "member-uuid") {
success
}
}]) %>
<%= raw(~S[mutation {
createOverride(scheduleId: "schedule-uuid", input: {
userId: "user-uuid"
startTime: "2026-06-07T17:00:00Z"
endTime: "2026-06-09T09:00:00Z"
}) {
id
}
}
mutation {
deleteOverride(id: "override-uuid") {
success
}
}]) %>
<%= raw(~S[mutation {
createEscalationPolicy(input: {
name: "Critical alerts"
repeatCount: 3
repeatIntervalMinutes: 15
}) {
id
name
}
}
mutation {
updateEscalationPolicy(id: "policy-uuid", input: {name: "Critical alerts (revised)"}) {
id
}
}
mutation {
deleteEscalationPolicy(id: "policy-uuid") {
success
}
}]) %>
<%= raw(~S[mutation {
createEscalationRule(escalationPolicyId: "policy-uuid", input: {
position: 0
delayMinutes: 5
}) {
id
}
}
mutation {
createEscalationTarget(escalationRuleId: "rule-uuid", input: {
targetType: "schedule"
scheduleId: "schedule-uuid"
}) {
id
}
}
mutation {
deleteEscalationTarget(id: "target-uuid") {
success
}
}]) %>
<%= raw(~S[mutation {
createMaintenanceWindow(input: {
name: "Quarterly firmware roll"
startsAt: "2026-06-01T05:00:00Z"
endsAt: "2026-06-01T09:00:00Z"
siteId: "site-uuid"
suppressAlerts: true
}) {
id
name
}
}
mutation {
updateMaintenanceWindow(id: "window-uuid", input: {endsAt: "2026-06-01T10:00:00Z"}) {
id
endsAt
}
}
mutation {
deleteMaintenanceWindow(id: "window-uuid") {
success
}
}]) %>
Subscribe to real-time events via WebSocket. Connect to
wss://app.towerops.net/socket/graphql
with your API token as a connection parameter.
Pass your API token in the connection parameters when establishing the WebSocket:
<%= raw(~S[// JavaScript example using @absinthe/socket
import { Socket as PhoenixSocket } from "phoenix";
import * as AbsintheSocket from "@absinthe/socket";
const phoenixSocket = new PhoenixSocket(
"wss://app.towerops.net/socket/graphql",
{ params: { token: "your-api-token" } }
);
const absintheSocket = AbsintheSocket.create(phoenixSocket);]) %>
Subscribe to device status changes. Optionally filter by a specific device ID, or omit to receive all device events in your organization.
| Argument | Type | Description |
|---|---|---|
| deviceId | ID | Optional — filter to a single device |
<%= raw(~S[subscription {
deviceStatusChanged(deviceId: "device-uuid") {
deviceId
deviceName
status
changedAt
}
}
# Or subscribe to all devices in your organization:
subscription {
deviceStatusChanged {
deviceId
deviceName
status
changedAt
}
}]) %>
Subscribe to alert lifecycle events (created, acknowledged, resolved) for your organization.
<%= raw(~S[subscription {
alertEvent {
alertId
alertType
severity
message
deviceId
eventType
triggeredAt
}
}]) %>
Subscribe to live sensor reading updates for a specific device. Delivers batched readings as they are polled.
| Argument | Type | Description |
|---|---|---|
| deviceId | ID! | Required device ID |
<%= raw(~S[subscription {
sensorReadingsUpdated(deviceId: "device-uuid") {
deviceId
deviceName
readings {
sensorId
sensorType
sensorDescr
sensorUnit
value
checkedAt
}
}
}]) %>
All field names use camelCase in GraphQL queries (Absinthe automatically converts from Elixir's snake_case).
id, name, ipAddress, description, displayOrder, status, lastCheckedAt, lastStatusChangeAt, monitoringEnabled, checkIntervalSeconds, snmpEnabled, snmpVersion, snmpCommunity, snmpCommunitySource, snmpPort, snmpTransport, snmpTransportSource, lastDiscoveryAt, lastSnmpPollAt, snmpv3SecurityLevel, snmpv3Username, snmpv3AuthProtocol, snmpv3PrivProtocol, snmpv3CredentialSource, mikrotikUsername, mikrotikPort, mikrotikSshPort, mikrotikUseSsl, mikrotikEnabled, mikrotikCredentialSource, deviceRole, deviceRoleSource, siteId, organizationId, insertedAt, updatedAt, site
id, name, description, location, displayOrder, snmpVersion, snmpCommunity, snmpPort, snmpTransport, snmpv3SecurityLevel, snmpv3Username, snmpv3AuthProtocol, snmpv3PrivProtocol, mikrotikUsername, mikrotikPort, mikrotikSshPort, mikrotikUseSsl, mikrotikEnabled, organizationId, agentTokenId, parentSiteId, insertedAt, updatedAt
id, alertType, message, triggeredAt, acknowledgedAt, resolvedAt, emailSentAt, deviceId, acknowledgedById, gaiiaImpact, insertedAt, device, acknowledgedByEmail
id, name, enabled, isCloudPoller, allowRemoteDebug, lastSeenAt, lastIp, metadata, organizationId, insertedAt, updatedAt, deviceCount
id, name, slug, subscriptionPlan, useSites, snmpVersion, snmpCommunity, snmpPort, snmpTransport, snmpv3SecurityLevel, snmpv3Username, snmpv3AuthProtocol, snmpv3PrivProtocol, mikrotikEnabled, mikrotikUsername, mikrotikPort, mikrotikSshPort, mikrotikUseSsl, defaultAgentTokenId, insertedAt, updatedAt
id, email, role, isDefault, userId, insertedAt
id, provider, enabled, syncIntervalMinutes, lastSyncedAt, lastSyncStatus, organizationId, insertedAt, updatedAt
summary, detail, timestamp, severity, icon, deviceName, siteName, link, type
id, sensorType, sensorUnit, sensorDescr, currentValue, lastCheckedAt, monitored
sensorId, value, status, checkedAt
timestamp, inBps (Float), outBps (Float), inErrors (Int), outErrors (Int)
checkId, value, status, checkedAt, responseTimeMs
deviceId, deviceName, status, changedAt
alertId, alertType, severity, message, deviceId, eventType, triggeredAt
deviceId, deviceName, readings (list of SensorReadingSnapshot: sensorId, sensorType, sensorDescr, sensorUnit, value, checkedAt)
DeleteResult:
success (Boolean!), message (String)
TestResult:
success (Boolean!), message (String)
MetricPoint:
timestamp, value, status, checkName, checkType
Interface:
id, ifIndex, ifName, ifDescr, ifType, ifSpeed, ifAdminStatus, ifOperStatus, ifAlias
Invitation:
id, email, role, expiresAt, acceptedAt, insertedAt
AgentWithToken:
id, name, enabled, token, insertedAt
curl -X POST https://app.towerops.net/api/graphql \
-H "Authorization: Bearer <%= @sample_token %>" \
-H "Content-Type: application/json" \
<%= raw(~S|-d '{"query": "{ devices { id name ipAddress status site { id name location } } }"}'|) %>
curl -X POST https://app.towerops.net/api/graphql \
-H "Authorization: Bearer <%= @sample_token %>" \
-H "Content-Type: application/json" \
<%= raw(~S|-d '{"query": "{ alerts(status: \"active\") { id alertType message triggeredAt device { name ipAddress } } }"}'|) %>
curl -X POST https://app.towerops.net/api/graphql \
-H "Authorization: Bearer <%= @sample_token %>" \
-H "Content-Type: application/json" \
<%= raw(~S|-d '{"query": "mutation { createDevice(input: { ipAddress: \"192.168.1.1\", name: \"Core Router\", snmpEnabled: true }) { id name status } }"}'|) %>
curl -X POST https://app.towerops.net/api/graphql \
-H "Authorization: Bearer <%= @sample_token %>" \
-H "Content-Type: application/json" \
<%= raw(~S|-d '{"query": "mutation { acknowledgeAlert(id: \"alert-uuid\") { id acknowledgedAt } }"}'|) %>
curl -X POST https://app.towerops.net/api/graphql \
-H "Authorization: Bearer <%= @sample_token %>" \
-H "Content-Type: application/json" \
<%= raw(~S|-d '{"query": "query GetDevice($id: ID!) { device(id: $id) { id name ipAddress status site { name } } }", "variables": {"id": "device-uuid"}}'|) %>