Developers

API documentation

The Infra Agent REST API gives you full programmatic control of your organization: create and manage monitors of every type, acknowledge and resolve incidents, configure alert channels, schedule maintenance windows, publish status pages, organize apps, and manage members and invitations from scripts, deploy pipelines, or your own tooling.

Base URL
https://infraagent.app/api/v1

Every response is JSON and includes a success flag. Failed requests return { "success": false, "error": "..." } with a matching HTTP status code.

Authentication

API keys are personal: each key belongs to the member who created it and acts with that member's permissions. A key can see and do exactly what its owner can in the dashboard, nothing more: an owner's key can manage the whole organization, a plain member's key only reaches the apps that member has been granted. If the owner's role changes the key follows, and it stops working the moment they leave the organization. Create keys under API in the dashboard. A full-access key can change or delete anything its owner can, while a read-only key can only list and read. The read-only key works for every GET endpoint; POST, PATCH, and DELETE require full access.

Treat every key like a password: keep it in environment variables or a secret manager, never in source control or client-side code, and use a read-only key wherever writing is not needed. The full key is shown once at creation, so store it right away. If a key leaks, revoke it from the dashboard; it stops working immediately.

Send the key with every request, either as a bearer token or an X-Api-Key header:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://infraagent.app/api/v1/monitors

curl -H "X-Api-Key: YOUR_API_KEY" \
  https://infraagent.app/api/v1/monitors

Apps

Monitors, alert channels, maintenance windows, and status pages each live inside an app (a project within your organization). Endpoints that create one of these accept an appIdfield. If your key can reach a single app you can omit it; with more than one it is required. A member's key only sees the apps that member has been granted. List your apps via GET /apps.

Errors

400The query parameters or request body failed validation. The error message names the offending field.
401The API key is missing or invalid.
403The key lacks access: a read-only key on a write endpoint, a non-admin's key on an admin-only endpoint or without any app access, or the request exceeds a plan limit (monitor count, check interval, status pages, seats, SMS).
404The resource does not exist or belongs to another organization.
412A required server-side integration is not configured (for example SMS delivery).

Endpoints

Monitors

GET/monitors

List every monitor in your organization, oldest first. Each monitor includes id, name, type, status, enabled, target, intervalSeconds, and check timestamps. Disabled monitors report their status as paused.

Query parameters
status
up | down | paused | pending
Only return monitors with this status.
type
http | tcp | ssl | heartbeat | dns | domain
Only return monitors of this type.
appId
string
Only return monitors in this app.
limit
integer, 1-500, default 100
Page size.
offset
integer, default 0
Number of monitors to skip.
GET/monitors/{id}

A single monitor with its full config, the latest 25 checks as recentChecks, and the currently open incident as openIncident (or null). Heartbeat monitors also include their ping URL as heartbeatUrl.

POST/monitorsFull access

Create a monitor. The config object depends on the monitor type; unlisted config fields get sensible defaults. Attach alert channels by passing channels as an array of { "channelId": "...", "notifyOn": "down" | "up" | "both" }. Returns 201 with the created monitor.

Body fields
name
string, required
Display name, 1-120 characters.
type
http | tcp | ssl | heartbeat | dns | domain, required
What kind of check to run.
config
object, required
Type-specific settings, see the table below.
intervalSeconds
integer, 30-86400, required
How often the monitor is checked. Plan limits apply; domain monitors check at most hourly.
enabled
boolean, default true
Start checking immediately.
channels
array, default []
Alert channels to notify, with per-channel notifyOn and optional messageTemplate.
appId
string
App to create the monitor in. Optional for single-app organizations.
Config by monitor type
http
url (required), method, expectedStatusRange, keyword, keywordMode, requestHeaders, followRedirects, timeoutMs, degradedMs
Checks a URL and optionally asserts a keyword is present or absent.
tcp
host (required), port (required), timeoutMs
Checks that a TCP port accepts connections.
ssl
host (required), port, warnDays, timeoutMs
Warns before the TLS certificate expires.
heartbeat
graceSeconds, token (optional, autogenerated)
Your job pings us; the monitor goes down when pings stop. The response includes heartbeatUrl.
dns
host (required), recordType, expectedValues, timeoutMs
Resolves a DNS record and optionally asserts its values.
domain
domain (required), warnDays, timeoutMs
Warns before the domain registration expires.
curl -X POST \
  -H "Authorization: Bearer YOUR_MAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing site",
    "type": "http",
    "intervalSeconds": 60,
    "config": { "url": "https://example.com/health" }
  }' \
  https://infraagent.app/api/v1/monitors
PATCH/monitors/{id}Full access

Update a monitor. Send a JSON body with at least one field; anything omitted is left unchanged. Setting enabled to false pauses the monitor, true resumes it. A provided config replaces the stored config wholesale, and a provided channels array replaces all channel attachments.

Body fields
name
string, 1-120 characters
Rename the monitor.
enabled
boolean
Pause (false) or resume (true) checks.
intervalSeconds
integer, 30-86400
How often the monitor is checked.
type
http | tcp | ssl | heartbeat | dns | domain
Change the monitor type. Send a matching config alongside it.
config
object
Replace the type-specific settings.
channels
array
Replace the attached alert channels.
POST/monitors/{id}/runFull access

Run the monitor's check immediately, outside its normal schedule, and return the result. Useful right after creating or reconfiguring a monitor.

DELETE/monitors/{id}Full access

Delete a monitor. Check history and past incidents are kept for your records, but the monitor stops running and disappears from lists immediately.

Incidents

GET/incidents

List incidents across all monitors, newest first. Each incident includes id, monitorId, monitorName, startedAt, resolvedAt, durationSeconds, cause, and lastError.

Query parameters
status
open | resolved
Only open (unresolved) or resolved incidents.
monitorId
string
Only incidents for this monitor.
limit
integer, 1-200, default 50
Page size.
offset
integer, default 0
Number of incidents to skip.
POST/incidents/{id}/acknowledgeFull access

Mark an incident as acknowledged so your team knows it is being handled.

POST/incidents/{id}/resolveFull access

Manually resolve an open incident. Most incidents resolve themselves when the monitor recovers; use this for stragglers.

Alert channels

GET/channels

List alert channels. Channel configs hold webhook URLs and provider tokens, so the config field is only included when using a full-access key.

GET/channels/{id}

A single alert channel. Same key rules as the list.

POST/channelsFull access

Create an alert channel. Supported types: email, sms, slack, discord, telegram, pushbullet, pushover, pagerduty, zapier, splunk, and webhook. New SMS phone numbers are texted a verification code (returned as codesSentTo) and must be confirmed in the dashboard before they receive alerts.

Body fields
type
string, required
One of the channel types above.
name
string, required
Display name, 1-120 characters.
config
object, required
Type-specific settings: webhookUrl for Slack/Discord/Zapier/webhook, recipients for email, phoneNumbers for SMS, botToken and chatId for Telegram, and so on. Validation errors name what is missing.
enabled
boolean, default true
Whether the channel sends alerts.
messageTemplate
string
Custom alert message template. Defaults to the standard template.
appId
string
App to create the channel in. Optional for single-app organizations.
PATCH/channels/{id}Full access

Update an alert channel. Send at least one of type, name, enabled, config, messageTemplate. A provided config replaces the stored one wholesale.

DELETE/channels/{id}Full access

Delete an alert channel and detach it from every monitor.

POST/channels/{id}/testFull access

Send a sample "down" alert through the channel to confirm it is wired up correctly. Returns the delivery result, or a 400 explaining why nothing was sent.

Maintenance windows

GET/maintenance-windows

List maintenance windows, newest first. While a window is active, matching monitors stay quiet: no alerts, no new incidents.

POST/maintenance-windowsFull access

Schedule a maintenance window. Set monitorId to quiet a single monitor, or leave it null to quiet the whole app.

Body fields
startsAt
ISO 8601 datetime, required
When the window opens.
endsAt
ISO 8601 datetime, required
When the window closes. Must be after startsAt.
monitorId
string or null
Limit the window to one monitor.
reason
string
Shown wherever the window is displayed.
appId
string
App the window applies to. Optional for single-app organizations.
GET/maintenance-windows/{id}

A single maintenance window.

PATCH/maintenance-windows/{id}Full access

Update a window's startsAt, endsAt, monitorId, or reason.

DELETE/maintenance-windows/{id}Full access

Delete a maintenance window. Alerts resume immediately.

Status pages

GET/status-pages

List status pages with their monitor counts.

GET/status-pages/{id}

A single status page with its placed monitors in display order.

POST/status-pagesFull access

Create a status page. Plan limits on the number of status pages apply. Place monitors by passing monitors as an array of { "monitorId": "...", "displayName": "...", "sortOrder": 0 }.

Body fields
title
string, required
Page title, 1-120 characters.
slug
string, required
Public address of the page. Lowercased and slugified.
description
string
Shown under the title.
isPublic
boolean, default true
Whether the page is publicly reachable.
monitors
array, default []
Monitors to place on the page.
appId
string
App to create the page in. Optional for single-app organizations.
PATCH/status-pages/{id}Full access

Update a status page. A provided monitorsarray replaces the page's monitor placement wholesale.

DELETE/status-pages/{id}Full access

Delete a status page. Its public URL stops working immediately.

Apps

GET/apps

List the organization's apps with their monitor counts.

POST/appsAdmin only

Create an app. Body: name (required) and an optional slug. Creating the first real app renames the auto-created "Default" app in place, keeping its monitors.

PATCH/apps/{id}Admin only

Rename an app or change its slug.

DELETE/apps/{id}Admin only

Delete an app and everything in it: monitors, alert channels, maintenance windows, and status pages. This cannot be undone.

Organization

GET/organization

The organization's name, slug, and logo.

PATCH/organizationAdmin only

Update the organization's name or slug.

GET/organization/members

List members with their role (owner, admin, or member), name, and email.

PATCH/organization/members/{id}Admin only

Change a member's role between member and admin. The owner's role can't be changed.

DELETE/organization/members/{id}Admin only

Remove a member from the organization. The owner can't be removed.

GET/organization/invitationsAdmin only

List pending invitations, including any pre-assigned apps.

POST/organization/invitationsAdmin only

Invite people by email. Each address receives an invitation email; re-inviting a pending address resends it. Plan seat limits apply.

Body fields
emails
array of strings, required
Up to 50 email addresses.
role
member | admin, default member
Role granted on acceptance.
appIds
array of strings, default []
Apps a plain member can see after joining. Admins always see every app.
DELETE/organization/invitations/{id}Admin only

Revoke a pending invitation so the emailed link stops working.

Billing

GET/billing

Read-only plan and usage overview: plan id and name, plan limits, current usage (monitors, status pages, members), and subscription status. Plan changes go through the dashboard's billing settings.

Example: pause a monitor

Pause checks during a deploy with a full-access key, then flip enabled back to true when you are done:

curl -X PATCH \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}' \
  https://infraagent.app/api/v1/monitors/{id}
Need a key? Create one under API in the dashboard. The full key is shown once at creation, so copy it then; you can revoke it there at any time.