docs(api): add Coverages, Maintenance Windows, Schedules, Escalation Policies

The /docs/api and /docs/graphql pages were missing four resource
families that the API has shipped:

- Coverages (RF coverage prediction with async compute, recompute,
  KMZ download)
- Maintenance Windows (one-off + recurring with RRULE)
- On-Call Schedules (top-level CRUD + layers, members, overrides,
  on_call lookup)
- Escalation Policies (CRUD + rules + targets)

Both REST and GraphQL pages now have sidebar entries and example
requests for each.
This commit is contained in:
Graham McIntire 2026-05-07 16:08:09 -05:00
parent 27e8eb316f
commit 973c08bc5c
2 changed files with 991 additions and 0 deletions

View file

@ -166,6 +166,42 @@
Graphs & Live Polling
</a>
</li>
<li>
<a
href="#coverages"
data-nav-link="coverages"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
RF Coverages
</a>
</li>
<li>
<a
href="#maintenance-windows"
data-nav-link="maintenance-windows"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Maintenance Windows
</a>
</li>
<li>
<a
href="#schedules"
data-nav-link="schedules"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
On-Call Schedules
</a>
</li>
<li>
<a
href="#escalation-policies"
data-nav-link="escalation-policies"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Escalation Policies
</a>
</li>
</ul>
</li>
@ -3864,6 +3900,506 @@ curl -G https://towerops.net/api/v1/activity \\
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Coverages Resource -->
<section id="coverages" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
RF Coverages
</h2>
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
RF coverage predictions model where each radio actually reaches. Compute is async — a created or recomputed coverage starts in
<code>queued</code>
and progresses through <code>computing</code>
to <code>ready</code>
or <code>failed</code>. The status field is present on every response so polling-based clients (Terraform, Ansible, scripts) can wait for a healthy resource. Outputs include a coloured PNG heatmap, a Float32 GeoTIFF raster, and a downloadable KMZ bundle for Google Earth.
</p>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">List all coverages</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>GET /api/v1/coverages</code>. Returns every coverage in the authenticated organization, regardless of status.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl -G https://towerops.net/api/v1/coverages \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Create a coverage</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>POST /api/v1/coverages</code>. Creates a new coverage and immediately enqueues compute. Required: <code>name</code>, <code>site_id</code>, <code>antenna_slug</code>, <code>frequency_mhz</code>, <code>tx_power_dbm</code>, <code>height_agl_m</code>, <code>azimuth_deg</code>, <code>radius_m</code>. Optional fields tune cell size, downtilt, foliage, receiver height, and threshold.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/coverages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"coverage": {
"name": "North sector 5 GHz",
"site_id": "550e8400-e29b-41d4-a716-446655440000",
"antenna_slug": "rf-elements-twistport-symmetrical-horn-30",
"frequency_mhz": 5800,
"tx_power_dbm": 22.0,
"height_agl_m": 30,
"azimuth_deg": 0,
"downtilt_deg": 2,
"radius_m": 6000,
"cell_size_m": 10
}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Retrieve a coverage</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>GET /api/v1/coverages/:id</code>. Returns one coverage including its bbox, status, progress percentage, and (when ready) the
<code>png_path</code>
+ <code>raster_path</code>
outputs.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl https://towerops.net/api/v1/coverages/COV_ID \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Update a coverage</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>PATCH /api/v1/coverages/:id</code>. Mutates editable fields (name, antenna parameters, radius, cell size, etc.). Does
<strong>not</strong>
auto-recompute — call the recompute endpoint when you want fresh outputs.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X PATCH https://towerops.net/api/v1/coverages/COV_ID \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"coverage": {"tx_power_dbm": 25.0}}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
Recompute a coverage
</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>POST /api/v1/coverages/:id/recompute</code>. Re-queues the compute pipeline without changing any parameters. Returns
<code>409 Conflict</code>
if the coverage is already computing. Useful after a parameter update or after the antenna catalog is refreshed.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl -X POST https://towerops.net/api/v1/coverages/COV_ID/recompute \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Download as KMZ</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>GET /api/v1/coverages/:id/kmz</code>. Returns a Google Earth-compatible KMZ bundle (KML + PNG). Returns
<code>409 Conflict</code>
if the coverage is not yet ready.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl -OJ https://towerops.net/api/v1/coverages/COV_ID/kmz \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Delete a coverage</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>DELETE /api/v1/coverages/:id</code>. Removes the coverage and any cached outputs. Returns
<code>204 No Content</code>
on success.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl -X DELETE https://towerops.net/api/v1/coverages/COV_ID \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Maintenance Windows Resource -->
<section id="maintenance-windows" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Maintenance Windows
</h2>
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Maintenance windows tell Towerops to suppress alerts for a site or device during planned work. Windows can be one-off or recurring (iCal RRULE).
</p>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
List maintenance windows
</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>GET /api/v1/maintenance_windows</code>. Optional <code>filter</code>
query param accepts <code>active</code>, <code>upcoming</code>, or <code>past</code>.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl -G https://towerops.net/api/v1/maintenance_windows \\
-H "Authorization: Bearer #{@sample_token}" \\
-d filter=active
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
Create a maintenance window
</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>POST /api/v1/maintenance_windows</code>. Required: <code>name</code>, <code>starts_at</code>, <code>ends_at</code>. Scope to a site or a specific device. Set
<code>recurring: true</code>
with a <code>recurrence_rule</code>
(RRULE) to repeat.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/maintenance_windows \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"maintenance_window": {
"name": "Quarterly firmware roll",
"starts_at": "2026-06-01T05:00:00Z",
"ends_at": "2026-06-01T09:00:00Z",
"site_id": "SITE_UUID",
"suppress_alerts": true
}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">
Get / update / delete
</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
Standard CRUD on <code>/api/v1/maintenance_windows/:id</code>. <code>GET</code>
returns the resource; <code>PATCH</code>
updates fields with the same body shape as create; <code>DELETE</code>
returns a JSON success body.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl -X DELETE https://towerops.net/api/v1/maintenance_windows/WINDOW_ID \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Schedules Resource -->
<section id="schedules" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
On-Call Schedules
</h2>
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Schedules drive who gets paged when an alert fires. A schedule contains one or more
<em>layers</em>
(rotations); each layer has ordered <em>members</em>. Ad-hoc <em>overrides</em>
let you swap the on-call user for a fixed time window without changing the rotation.
</p>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Schedule CRUD</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>GET /api/v1/schedules</code>, <code>POST</code>, <code>GET /:id</code>, <code>PATCH /:id</code>, <code>DELETE /:id</code>. Required on create: <code>name</code>, <code>timezone</code>. Showing one schedule returns its layers + overrides nested.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/schedules \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"schedule": {
"name": "Primary on-call",
"description": "Weekly rotation",
"timezone": "America/Chicago"
}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Who is on call?</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>GET /api/v1/schedules/:id/on_call</code>. Returns the user currently on call (taking layers and overrides into account), or
<code>null</code>
if nobody is.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw("""
curl https://towerops.net/api/v1/schedules/SCHED_ID/on_call \\
-H "Authorization: Bearer #{@sample_token}"
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Layers and members</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>POST /api/v1/schedules/:id/layers</code>, <code>PATCH /api/v1/schedules/:id/layers/:layer_id</code>,
<code>DELETE</code>
the same. A layer requires <code>name</code>, <code>position</code>,
<code>rotation_type</code>
(<code>weekly</code>/<code>daily</code>/<code>custom</code>), <code>rotation_interval</code>, <code>handoff_time</code>, and <code>start_date</code>.
<br /><br /> Add and remove members with
<code>POST /:id/layers/:layer_id/members</code>
(body: <code>user_id</code>, <code>position</code>) and <code>DELETE /:id/layers/:layer_id/members/:member_id</code>.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/schedules/SCHED_ID/layers \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"layer": {
"name": "Primary",
"position": 0,
"rotation_type": "weekly",
"rotation_interval": 1,
"handoff_time": "09:00:00",
"start_date": "2026-06-01T00:00:00Z"
}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Overrides</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>POST /api/v1/schedules/:id/overrides</code>
creates a one-off cover ("Bob is on for Alice from Friday 17:00 to Monday 09:00"). Required: <code>user_id</code>, <code>start_time</code>, <code>end_time</code>. Remove with <code>DELETE /:id/overrides/:override_id</code>.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/schedules/SCHED_ID/overrides \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"override": {
"user_id": "USER_UUID",
"start_time": "2026-06-07T17:00:00Z",
"end_time": "2026-06-09T09:00:00Z"
}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Escalation Policies Resource -->
<section id="escalation-policies" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
Escalation Policies
</h2>
<p class="mt-4 text-base text-gray-600 dark:text-gray-400">
Escalation policies are an ordered list of <em>rules</em>; each rule fires its
<em>targets</em>
after a delay if the previous rule's targets haven't acknowledged the alert. Targets can reference users, schedules, or arbitrary webhooks.
</p>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Policy CRUD</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
Standard REST CRUD under <code>/api/v1/escalation_policies</code>.
<code>GET /:id</code>
returns the policy with its rules and targets nested. Required on create: <code>name</code>. Optional: <code>description</code>, <code>repeat_count</code>, <code>repeat_interval_minutes</code>.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/escalation_policies \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"escalation_policy": {
"name": "Critical alerts",
"description": "Page primary, then secondary, then manager",
"repeat_count": 3,
"repeat_interval_minutes": 15
}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Rules</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
<code>POST /api/v1/escalation_policies/:id/rules</code>
appends a rule. <code>PATCH /api/v1/escalation_policies/:id/rules/:rule_id</code>
updates one. <code>DELETE</code>
removes one. Required on create: <code>position</code>, <code>delay_minutes</code>.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/escalation_policies/POLICY_ID/rules \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rule": {"position": 0, "delay_minutes": 5}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
<div class="mt-12">
<h3 class="text-xl font-semibold text-zinc-900 dark:text-white">Targets</h3>
<div class="mt-4 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-2">
<div>
<p class="text-base text-gray-600 dark:text-gray-400">
Each rule has one or more targets:
<code>POST /api/v1/escalation_policies/:id/rules/:rule_id/targets</code>
creates one,
<code>
DELETE /api/v1/escalation_policies/:id/rules/:rule_id/targets/:target_id
</code>
removes it. A target body specifies <code>target_type</code>
(<code>user</code>, <code>schedule</code>, or <code>webhook</code>) plus the corresponding identifier or URL.
</p>
</div>
<div>
<div class="overflow-hidden rounded-lg bg-gray-900 dark:bg-gray-950">
<pre class="p-4 text-sm text-zinc-100 overflow-x-auto"><code><%= raw(~S"""
curl -X POST https://towerops.net/api/v1/escalation_policies/POLICY_ID/rules/RULE_ID/targets \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"target": {"target_type": "schedule", "schedule_id": "SCHED_UUID"}
}'
""") %></code></pre>
</div>
</div>
</div>
</div>
</section>
<hr class="my-16 border-gray-200 dark:border-white/10" />
<!-- Terraform Provider Section -->
<section id="terraform" class="scroll-mt-24 mb-16">
<h2 class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">

View file

@ -126,6 +126,38 @@
Time-Series
</a>
</li>
<li>
<a
href="#query-checks"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Service Checks
</a>
</li>
<li>
<a
href="#query-schedules"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
On-Call Schedules
</a>
</li>
<li>
<a
href="#query-escalation-policies"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Escalation Policies
</a>
</li>
<li>
<a
href="#query-maintenance-windows"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Maintenance Windows
</a>
</li>
</ul>
</li>
@ -189,6 +221,38 @@
Integrations
</a>
</li>
<li>
<a
href="#mutation-checks"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Service Checks
</a>
</li>
<li>
<a
href="#mutation-schedules"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Schedules
</a>
</li>
<li>
<a
href="#mutation-escalation-policies"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Escalation Policies
</a>
</li>
<li>
<a
href="#mutation-maintenance-windows"
class="nav-link block py-1 pl-4 pr-3 text-sm text-gray-600 transition hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
>
Maintenance Windows
</a>
</li>
</ul>
</li>
@ -841,6 +905,179 @@
</div>
</section>
<!-- Queries: Service Checks -->
<section id="query-checks" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Service Checks
</h2>
<p class="mt-2 text-base text-gray-600 dark:text-gray-400">
List and inspect HTTP, TCP, DNS, and ping service checks.
</p>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">checks</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
checks(checkType: "http", deviceId: "device-uuid") {
id
name
checkType
enabled
intervalSeconds
currentState
config
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">check (single)</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
check(id: "check-uuid") {
id
name
checkType
config
currentState
currentStateType
lastCheckAt
}
}]) %></code></pre>
</div>
</section>
<!-- Queries: Schedules -->
<section id="query-schedules" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: On-Call Schedules
</h2>
<p class="mt-2 text-base text-gray-600 dark:text-gray-400">
Inspect schedules and find out who is currently on call.
</p>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">schedules</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
schedules {
id
name
timezone
description
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">
schedule (with layers + overrides)
</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
schedule(id: "schedule-uuid") {
id
name
timezone
layers {
id
name
position
rotationType
members {
userId
position
}
}
overrides {
id
userId
startTime
endTime
}
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">onCall</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
onCall(scheduleId: "schedule-uuid") {
userId
email
}
}]) %></code></pre>
</div>
</section>
<!-- Queries: Escalation Policies -->
<section id="query-escalation-policies" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Escalation Policies
</h2>
<p class="mt-2 text-base text-gray-600 dark:text-gray-400">
Inspect escalation policies and their rules + targets.
</p>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">escalationPolicies</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
escalationPolicies {
id
name
description
repeatCount
repeatIntervalMinutes
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">
escalationPolicy (with rules + targets)
</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
escalationPolicy(id: "policy-uuid") {
id
name
rules {
id
position
delayMinutes
targets {
id
targetType
userId
scheduleId
}
}
}
}]) %></code></pre>
</div>
</section>
<!-- Queries: Maintenance Windows -->
<section id="query-maintenance-windows" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Query: Maintenance Windows
</h2>
<p class="mt-2 text-base text-gray-600 dark:text-gray-400">
Inspect planned and active maintenance windows. The optional <code>filter</code>
argument accepts <code>active</code>, <code>upcoming</code>, or <code>past</code>.
</p>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">maintenanceWindows</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[{
maintenanceWindows(filter: "upcoming") {
id
name
startsAt
endsAt
suppressAlerts
siteId
deviceId
}
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Devices -->
<section id="mutation-devices" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
@ -1070,6 +1307,224 @@ mutation { cancelInvitation(id: "invitation-uuid") { success message } }]) %></c
</div>
</section>
<!-- Mutations: Service Checks -->
<section id="mutation-checks" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Service Checks
</h2>
<h3 class="mt-6 text-lg font-semibold text-zinc-900 dark:text-white">createCheck</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">
updateCheck / deleteCheck
</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= raw(~S[mutation {
updateCheck(id: "check-uuid", input: {intervalSeconds: 30}) {
id
intervalSeconds
}
}
mutation {
deleteCheck(id: "check-uuid") {
success
}
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Schedules -->
<section id="mutation-schedules" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Schedules
</h2>
<h3 class="mt-6 text-lg font-semibold text-zinc-900 dark:text-white">Schedule CRUD</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">Layers + members</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">Overrides</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Escalation Policies -->
<section id="mutation-escalation-policies" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Escalation Policies
</h2>
<h3 class="mt-6 text-lg font-semibold text-zinc-900 dark:text-white">Policy CRUD</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
<h3 class="mt-8 text-lg font-semibold text-zinc-900 dark:text-white">Rules + targets</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
</section>
<!-- Mutations: Maintenance Windows -->
<section id="mutation-maintenance-windows" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">
Mutation: Maintenance Windows
</h2>
<h3 class="mt-6 text-lg font-semibold text-zinc-900 dark:text-white">CRUD</h3>
<div class="mt-4 rounded-lg bg-zinc-900 p-4 dark:bg-zinc-800">
<pre class="text-sm text-green-400 overflow-x-auto"><code><%= 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
}
}]) %></code></pre>
</div>
</section>
<!-- Subscriptions -->
<section id="subscriptions" class="mb-16">
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white">