GraphQL API

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-blue-600 hover:text-blue-500 dark:text-blue-400" > REST API and provides equivalent functionality with the added benefit of nested queries and precise field selection.

Authentication

Authenticate using a Bearer token in the Authorization header. API tokens can be created in your organization settings.

Authorization: Bearer <%= @sample_token %>

Endpoint

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 } }"}'|) %>

Query: Devices

devices

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
    }
  }
}]) %>

device

Get a single device by ID.

<%= raw(~S[{
  device(id: "device-uuid") {
    id
    name
    ipAddress
    status
    description
    snmpVersion
    snmpPort
    checkIntervalSeconds
    site { id name }
  }
}]) %>

Query: Sites

sites

List all sites for the organization.

<%= raw(~S[{
  sites {
    id
    name
    description
    location
    snmpVersion
    snmpCommunity
    insertedAt
  }
}]) %>

site

Get a single site by ID.

<%= raw(~S[{ site(id: "site-uuid") { id name location } }]) %>

Query: Alerts

alerts

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
  }
}]) %>

Query: Agents

<%= raw(~S[{
  agents {
    id
    name
    enabled
    lastSeenAt
    lastIp
    isCloudPoller
    deviceCount
    metadata
  }
}

# Single agent
{ agent(id: "agent-uuid") { id name enabled deviceCount } }]) %>

Query: Organization

<%= raw(~S[{
  organization {
    id
    name
    slug
    subscriptionPlan
    useSites
    snmpVersion
    snmpCommunity
    snmpPort
    snmpTransport
    mikrotikEnabled
    mikrotikUsername
    mikrotikPort
    mikrotikUseSsl
    defaultAgentTokenId
  }
}]) %>

Query: Members

<%= raw(~S[{
  members {
    id
    email
    role
    insertedAt
  }
}]) %>

Query: Integrations

<%= raw(~S[{
  integrations {
    id
    provider
    enabled
    syncIntervalMinutes
    lastSyncedAt
    lastSyncStatus
  }
}]) %>

Query: Activity

<%= raw(~S[{
  activity(limit: 20) {
    summary
    detail
    timestamp
    severity
    deviceName
    siteName
    link
    type
  }
}]) %>

Query: Metrics & Interfaces

deviceMetrics

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
  }
}]) %>

deviceInterfaces

Get SNMP interfaces for a device.

<%= raw(~S[{
  deviceInterfaces(deviceId: "device-uuid") {
    id
    ifIndex
    ifName
    ifDescr
    ifType
    ifSpeed
    ifAdminStatus
    ifOperStatus
    ifAlias
  }
}]) %>

Mutation: Devices

createDevice

<%= 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
  }
}]) %>

updateDevice

<%= raw(~S[mutation {
  updateDevice(id: "device-uuid", input: {
    name: "Updated Router"
    monitoringEnabled: false
  }) {
    id
    name
    monitoringEnabled
  }
}]) %>

deleteDevice

<%= raw(~S[mutation {
  deleteDevice(id: "device-uuid") {
    success
    message
  }
}]) %>

Mutation: Sites

createSite

<%= raw(~S[mutation {
  createSite(input: {
    name: "Main Office"
    location: "New York, NY"
    snmpCommunity: "public"
  }) {
    id
    name
    location
  }
}]) %>

updateSite / deleteSite

Same pattern as device mutations.

Mutation: Alert Actions

acknowledgeAlert

<%= raw(~S[mutation {
  acknowledgeAlert(id: "alert-uuid") {
    id
    acknowledgedAt
    acknowledgedByEmail
  }
}]) %>

resolveAlert

<%= raw(~S[mutation {
  resolveAlert(id: "alert-uuid") {
    id
    resolvedAt
  }
}]) %>

Mutation: Agent Management

createAgent

Creates a new agent token. The raw token is only returned once.

<%= raw(~S[mutation {
  createAgent(name: "DC1 Agent") {
    id
    name
    token
  }
}]) %>

deleteAgent

<%= raw(~S[mutation { deleteAgent(id: "agent-uuid") { success message } }]) %>

Mutation: Organization Settings

<%= 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
  }
}]) %>

Mutation: Members

sendInvitation

<%= raw(~S[mutation {
  sendInvitation(email: "user@example.com", role: "admin") {
    id
    email
    role
    expiresAt
  }
}]) %>

updateMemberRole

<%= raw(~S[mutation {
  updateMemberRole(id: "user-uuid", role: "admin") {
    id
    email
    role
  }
}]) %>

removeMember / cancelInvitation

<%= raw(~S[mutation { removeMember(id: "user-uuid") { success message } }
mutation { cancelInvitation(id: "invitation-uuid") { success message } }]) %>

Mutation: Integrations

createIntegration

<%= raw(~S[mutation {
  createIntegration(input: {
    provider: "preseem"
    enabled: true
    credentials: "{\"api_key\": \"xxx\"}"
    syncIntervalMinutes: 10
  }) {
    id
    provider
    enabled
  }
}]) %>

testIntegration

<%= raw(~S[mutation {
  testIntegration(id: "integration-uuid") {
    success
    message
  }
}]) %>

Types Reference

All field names use camelCase in GraphQL queries (Absinthe automatically converts from Elixir's snake_case).

Device

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

Site

id, name, description, location, displayOrder, snmpVersion, snmpCommunity, snmpPort, snmpTransport, snmpv3SecurityLevel, snmpv3Username, snmpv3AuthProtocol, snmpv3PrivProtocol, mikrotikUsername, mikrotikPort, mikrotikSshPort, mikrotikUseSsl, mikrotikEnabled, organizationId, agentTokenId, parentSiteId, insertedAt, updatedAt

Alert

id, alertType, message, triggeredAt, acknowledgedAt, resolvedAt, emailSentAt, deviceId, acknowledgedById, gaiiaImpact, insertedAt, device, acknowledgedByEmail

Agent

id, name, enabled, isCloudPoller, allowRemoteDebug, lastSeenAt, lastIp, metadata, organizationId, insertedAt, updatedAt, deviceCount

Organization

id, name, slug, subscriptionPlan, useSites, snmpVersion, snmpCommunity, snmpPort, snmpTransport, snmpv3SecurityLevel, snmpv3Username, snmpv3AuthProtocol, snmpv3PrivProtocol, mikrotikEnabled, mikrotikUsername, mikrotikPort, mikrotikSshPort, mikrotikUseSsl, defaultAgentTokenId, insertedAt, updatedAt

Member

id, email, role, isDefault, userId, insertedAt

Integration

id, provider, enabled, syncIntervalMinutes, lastSyncedAt, lastSyncStatus, organizationId, insertedAt, updatedAt

ActivityItem

summary, detail, timestamp, severity, icon, deviceName, siteName, link, type

Utility Types

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 Examples

List devices with site info

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 } } }"}'|) %>

Get active alerts

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 } } }"}'|) %>

Create a device

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 } }"}'|) %>

Acknowledge an alert

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 } }"}'|) %>

Using variables

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"}}'|) %>