IndiePulse Docs / API Reference

API Reference

REST API for programmatic access to your monitoring data. Full CRUD on monitors, incident lifecycle management, and AI agent integration via MCP.


Quick Start

Setting up an AI agent? See the Agent Quick Start → for a focused 5-minute guide.

1. Get your API key

Generate an API key in your Settings → API page. All plans include API access.

2. Make your first request

curl https://indiepulse.dev/api/v1/status \
  -H "Authorization: Bearer ip_live_your_key_here"

3. Set up MCP (for AI agents)

Add IndiePulse to your Claude, Cursor, or any MCP-compatible client:

{
  "mcpServers": {
    "indiepulse": {
      "command": "npx",
      "args": ["-y", "@indiepulse/mcp"],
      "env": { "INDIEPULSE_API_KEY": "ip_live_..." }
    }
  }
}

Then ask Claude: “Check my IndiePulse monitors”. See the MCP Server section for full setup.


Authentication

All API requests require a Bearer token in the Authorization header. Generate an API key in your Settings → API page.

Free tier — read endpoints + monitor management (create, update, delete, pause, resume) + acknowledge incidents. Paid plans — everything above + resolve incidents, post status updates, trigger instant checks, and manage maintenance.

# Example request
curl https://indiepulse.dev/api/v1/monitors \
-H "Authorization: Bearer ip_live_your_key_here"

Write responses include a meta.request_id field for debugging and correlation. All actions performed via API are recorded in the audit trail with your API key name.

Rate Limits

Rate limits are applied per API key. Responses include X-RateLimit-Limit-Minute and X-RateLimit-Limit-Day headers.

PlanAccessPer MinutePer DayMax Keys
FreeRead + Ack105001
HackerFull605,0002
MakerFull12020,0005
FounderFull300100,00010

Monitor States

Monitors expose two state fields. Use monitor_state for dashboards and alerting logic. Use status only for the raw consensus result of the latest check round.

FieldPurposeValues
statusLatest consensus check resultUP, DOWN, DEGRADED
monitor_stateOperational state machinePENDING, UP, INVESTIGATING, DOWN, RECOVERING, PAUSED, MAINTENANCE

Why two fields? A monitor can show status: UP while monitor_state is still RECOVERING (waiting for sustained recovery). The state machine prevents flapping on intermittent issues.

Uptime Calculation

The uptime_percent field uses time-based calculation:

(total_period - confirmed_incident_duration) / total_period * 100

Only INCIDENT events reduce uptime. PERFORMANCE degradations do not. Returns null when no check data exists.

Event Types

TypeMeaningAffects Uptime?
INCIDENTConfirmed downtimeYes
PERFORMANCESustained slow responsesNo
MAINTENANCEScheduled maintenance windowNo

Monitors

GET/api/v1/monitorsFree

List all monitors in your workspace

Parameters: page (default: 1), per_page (default: 50, max: 100)

Response:

{
  "data": [
    {
      "id": "uuid",
      "name": "My Website",
      "url": "https://example.com",
      "status": "UP",
      "monitor_state": "UP",
      "monitor_type": "http",
      "check_interval": 300,
      "last_heartbeat_at": null,
      "created_at": "2026-01-15T10:00:00Z",
      "last_checked_at": "2026-02-15T12:00:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 3, "total_pages": 1 }
}
GET/api/v1/monitors/:idFree

Get monitor details with 24-hour stats

Response:

{
  "data": {
    "id": "uuid",
    "name": "My Website",
    "url": "https://example.com",
    "status": "UP",
    "monitor_state": "UP",
    "monitor_type": "http",
    "check_interval": 300,
    "vigor": {
      "overall": 87,
      "label": "Good",
      "axes": { "network": 94, "security": 91, "response": 82, "frontend": null, "global": 78, "reliability": 95 }
    },
    "stats_24h": {
      "total_checks": 1440,
      "down_count": 0,
      "degraded_count": 12,
      "uptime_percent": 100.0
    }
  }
}

// Vigor: 0-100 per axis. network (DNS/TCP), security (TLS/SSL),
// response (TTFB), frontend (PageSpeed, null for API monitors),
// global (regional variance), reliability (uptime/broken links).
//
// For heartbeat monitors, stats_24h returns:
// { "total_pings": 24, "successful": 24, "failed": 0 }
GET/api/v1/monitors/:id/checksFree

Recent check results or heartbeat pings

Parameters: page (default: 1), per_page (default: 50, max: 100)

Response:

{
  "data": [
    {
      "id": "uuid",
      "status": "UP",
      "response_time": 142,
      "status_code": 200,
      "checked_at": "2026-02-15T12:00:00Z",
      "region": "iad"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 1440, "total_pages": 29, "retention_days": 30 }
}

// Heartbeat monitors return pings instead:
// "data": [{ "id": "uuid", "pinged_at": "...", "source_ip": "...", "ping_type": "success" }]
// "meta": { ..., "data_type": "heartbeat_pings" }
GET/api/v1/monitors/:id/domain-healthFree

Domain expiry + DNS record data

Response:

{
  "data": {
    "domain": {
      "monitored_domain": "example.com",
      "registrar": "Cloudflare, Inc.",
      "expiry_date": "2027-08-13T00:00:00Z",
      "days_remaining": 543,
      "transfer_locked": true
    },
    "dns_baselines": [
      { "record_type": "A", "record_values": ["93.184.216.34"], "ttl": 300, "dnssec_valid": true }
    ],
    "dns_changes": [
      { "record_type": "MX", "change_type": "modified", "previous_values": ["..."], "new_values": ["..."] }
    ]
  }
}
POST/api/v1/monitorsFree

Create a new HTTP monitor

Request Body:

{
  "name": "My API",                          // required
  "url": "https://api.example.com/health",   // required
  "check_interval": 300,                     // seconds (min depends on plan)
  "method": "GET",                           // GET, HEAD, POST, PUT, PATCH, DELETE
  "expected_status_code": 200,               // 100-599
  "timeout": 30,                             // 1-120 seconds
  "headers": { "X-Custom": "value" },        // optional
  "body": null,                              // optional request body
  "follow_redirects": true,                  // default: true
  "verify_ssl": true,                        // default: true
  "regions": ["iad", "ams", "sin"]           // subset of: iad, ams, sin, syd, gru
}

Response:

// 201 Created
{
  "data": {
    "id": "uuid",
    "name": "My API",
    "url": "https://api.example.com/health",
    "monitor_type": "http",
    "monitor_state": "PENDING",
    "check_interval": 300,
    "created_at": "2026-03-09T10:00:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

curl:

curl -X POST https://indiepulse.dev/api/v1/monitors \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "My API", "url": "https://api.example.com/health", "check_interval": 300}'

Validates against plan limits (monitor count, check interval minimum, region count). An instant check is triggered automatically after creation.

PATCH/api/v1/monitors/:idFree

Update monitor configuration

Request Body:

// All fields optional (partial update)
{
  "name": "Updated Name",
  "url": "https://new-url.example.com",
  "check_interval": 60,
  "method": "POST",
  "expected_status_code": 201,
  "timeout": 10,
  "headers": { "Authorization": "Bearer token" },
  "follow_redirects": false,
  "verify_ssl": true
}

Response:

{
  "data": {
    "id": "uuid",
    "name": "Updated Name",
    "url": "https://new-url.example.com",
    "monitor_type": "http",
    "monitor_state": "UP",
    "check_interval": 60,
    "created_at": "2026-01-15T10:00:00Z",
    "last_checked_at": "2026-03-09T12:00:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

curl:

curl -X PATCH https://indiepulse.dev/api/v1/monitors/MONITOR_ID \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "Updated Name", "check_interval": 60}'

monitor_type cannot be changed after creation.

DELETE/api/v1/monitors/:idFree

Soft-delete a monitor

Response:

{
  "data": {
    "id": "uuid",
    "name": "My Website",
    "deleted_at": "2026-03-09T10:00:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

curl:

curl -X DELETE https://indiepulse.dev/api/v1/monitors/MONITOR_ID \
  -H "Authorization: Bearer ip_live_your_key_here"

Auto-resolves any open incidents and insights linked to this monitor.

POST/api/v1/monitors/:id/pauseFree

Pause monitoring

Response:

{
  "data": {
    "id": "uuid",
    "name": "My Website",
    "monitor_state": "PAUSED"
  },
  "meta": { "request_id": "req_abc123" }
}

Stops checks and auto-resolves open incidents. Returns 409 if already paused.

POST/api/v1/monitors/:id/resumeFree

Resume a paused monitor

Response:

{
  "data": {
    "id": "uuid",
    "name": "My Website",
    "monitor_state": "PENDING"
  },
  "meta": { "request_id": "req_abc123" }
}

Triggers an immediate check. Returns 409 if not paused.

POST/api/v1/monitors/:id/checkPaid

Trigger an instant check

Response:

// 202 Accepted
{
  "data": {
    "monitor_id": "uuid",
    "check_requested_at": "2026-03-09T10:00:00Z",
    "message": "Instant check enqueued"
  },
  "meta": { "request_id": "req_abc123" }
}

60-second cooldown per monitor. Cannot check a paused monitor.

Events & Incidents

GET/api/v1/eventsFree

List events (incidents, performance, maintenance)

Parameters: page, per_page, type (INCIDENT | PERFORMANCE | MAINTENANCE), status (e.g. "Resolved")

Response:

{
  "data": [
    {
      "id": "uuid",
      "type": "INCIDENT",
      "title": "API Gateway Down",
      "status": "Resolved",
      "severity": "critical",
      "created_at": "2026-02-14T08:00:00Z",
      "resolved_at": "2026-02-14T08:45:00Z",
      "monitor_id": "uuid"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 12, "total_pages": 1 }
}
GET/api/v1/events/:idFree

Event detail with update timeline and audit trail

Response:

{
  "data": {
    "id": "uuid",
    "type": "INCIDENT",
    "title": "API Gateway Down",
    "status": "Resolved",
    "severity": "critical",
    "created_at": "2026-02-14T08:00:00Z",
    "resolved_at": "2026-02-14T08:45:00Z",
    "monitor_id": "uuid",
    "created_via": "api",
    "created_by_label": "prod-agent",
    "resolved_via": "api",
    "resolved_by_label": "prod-agent",
    "updates": [
      { "id": "uuid", "status": "Investigating", "message": "Looking into it", "created_at": "...", "created_via": "api", "created_by_label": "prod-agent" },
      { "id": "uuid", "status": "Resolved", "message": "Fixed", "created_at": "...", "created_via": "api", "created_by_label": "prod-agent" }
    ]
  }
}

The audit trail fields (created_via, resolved_via, *_by_label) show which API key or user performed each action.

POST/api/v1/eventsPaid

Create a manual incident or maintenance

Request Body:

// Incident
{
  "title": "API degradation",                    // required
  "type": "INCIDENT",                            // INCIDENT or MAINTENANCE
  "status": "Investigating",                     // Investigating | Identified | Monitoring
  "severity": "high",                            // low | medium | high | critical
  "visibility": "PUBLIC",                        // PUBLIC | INTERNAL
  "monitor_id": "uuid",                          // optional
  "message": "Seeing elevated error rates"        // optional first status update
}

// Maintenance
{
  "title": "Database migration",
  "type": "MAINTENANCE",
  "scheduled_start_at": "2026-03-15T02:00:00Z",  // required
  "scheduled_end_at": "2026-03-15T04:00:00Z",    // required, after start
  "monitor_id": "uuid",
  "message": "Planned schema migration"
}

Response:

// 201 Created
{
  "data": {
    "id": "uuid",
    "type": "INCIDENT",
    "title": "API degradation",
    "status": "Investigating",
    "severity": "high",
    "visibility": "PUBLIC",
    "created_at": "2026-03-09T10:00:00Z",
    "monitor_id": "uuid",
    "created_via": "api",
    "created_by_label": "prod-agent"
  },
  "meta": { "request_id": "req_abc123" }
}

curl:

curl -X POST https://indiepulse.dev/api/v1/events \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"title": "API degradation", "severity": "high"}'
POST/api/v1/events/:id/acknowledgeFree

Acknowledge an incident

Request Body:

{
  "message": "Looking into this"  // optional
}

Response:

{
  "data": {
    "id": "uuid",
    "title": "API Gateway Down",
    "status": "Investigating",
    "acknowledged_at": "2026-03-09T10:05:00Z",
    "acknowledged_via": "api",
    "acknowledged_by_label": "prod-agent",
    "escalation_paused_until": "2026-03-09T10:35:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

Available on all plans including free tier. API acknowledgements PAUSE escalations for 30 minutes (configurable per workspace) instead of cancelling them. If the agent doesn't resolve in time, escalations resume and humans get paged. Idempotent — acknowledging twice returns 200.

POST/api/v1/events/:id/updatePaid

Post a status update

Request Body:

{
  "status": "Identified",                        // optional status change
  "message": "Root cause: bad deploy at 3:42pm"  // required
}

Response:

// 201 Created
{
  "data": {
    "event_id": "uuid",
    "update_id": "uuid",
    "status": "Identified",
    "message": "Root cause: bad deploy at 3:42pm",
    "created_at": "2026-03-09T10:10:00Z",
    "created_via": "api",
    "created_by_label": "prod-agent"
  },
  "meta": { "request_id": "req_abc123" }
}

curl:

curl -X POST https://indiepulse.dev/api/v1/events/EVENT_ID/update \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"status": "Identified", "message": "Bad deploy identified, rolling back"}'
POST/api/v1/events/:id/resolvePaid

Resolve an event

Request Body:

{
  "message": "Reverted bad commit, confirmed recovery"  // optional
}

Response:

{
  "data": {
    "id": "uuid",
    "title": "API Gateway Down",
    "status": "Resolved",
    "resolved_at": "2026-03-09T10:15:00Z",
    "resolved_via": "api",
    "resolved_by_label": "prod-agent"
  },
  "meta": { "request_id": "req_abc123" }
}

curl:

curl -X POST https://indiepulse.dev/api/v1/events/EVENT_ID/resolve \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"message": "Reverted bad commit, confirmed recovery"}'

INCIDENT/PERFORMANCE events become "Resolved". MAINTENANCE events become "Completed". Triggers resolution webhooks.

POST/api/v1/events/:id/startPaid

Start scheduled maintenance

Response:

{
  "data": {
    "id": "uuid",
    "title": "Database migration",
    "type": "MAINTENANCE",
    "status": "In Progress",
    "scheduled_start_at": "2026-03-15T02:00:00Z",
    "scheduled_end_at": "2026-03-15T04:00:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

MAINTENANCE only. Transitions Scheduled to In Progress. If scheduled_start_at is in the future, it adjusts to now. Idempotent.

POST/api/v1/events/:id/completePaid

Complete maintenance (end early or on schedule)

Request Body:

{
  "message": "Migration completed successfully"  // optional
}

Response:

{
  "data": {
    "id": "uuid",
    "title": "Database migration",
    "type": "MAINTENANCE",
    "status": "Completed",
    "resolved_at": "2026-03-15T03:30:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

MAINTENANCE only. Must be "In Progress" status.

POST/api/v1/events/:id/cancelPaid

Cancel scheduled maintenance

Response:

{
  "data": {
    "id": "uuid",
    "title": "Database migration",
    "type": "MAINTENANCE",
    "status": "Cancelled",
    "resolved_at": "2026-03-09T10:00:00Z"
  },
  "meta": { "request_id": "req_abc123" }
}

MAINTENANCE only. Must be "Scheduled" status — cannot cancel maintenance already in progress.

Status

GET/api/v1/statusFree

Workspace health summary

Response:

{
  "data": {
    "monitors": { "total": 10, "up": 9, "down": 1, "unknown": 0 },
    "heartbeats": { "total": 3, "healthy": 3, "missed": 0 },
    "domains": { "monitored": 5, "all_healthy": true, "expiring_soon": [] },
    "active_incidents": [
      {
        "id": "uuid",
        "type": "INCIDENT",
        "title": "API issues",
        "status": "Investigating",
        "severity": "major",
        "created_at": "..."
      }
    ],
    "active_performance_events": [],
    "overall_status": "degraded"
  }
}

overall_status: "operational", "performance_degraded", or "degraded".

Heartbeat

GET/POST/HEAD/api/v1/heartbeat/:tokenPublic

Send a heartbeat ping from your cron jobs or scripts

Response:

{
  "ok": true,
  "monitor_id": "uuid",
  "name": "Nightly Backup"
}

No auth required — the token in the URL is the credential. Rate limited to 1 ping per 10 seconds per token.

POST/api/v1/heartbeat/:token/failPublic

Signal a failure explicitly

Request Body:

{
  "error": "Backup failed: disk full",  // optional
  "exit_code": 1                        // optional
}

Response:

{
  "ok": true,
  "monitor_id": "uuid",
  "ping_type": "fail"
}

No auth required. Triggers immediate incident creation. Rate limited to 1 fail per 5 minutes per token.

Code Examples

curl

# Check workspace health
curl -s https://indiepulse.dev/api/v1/status \
  -H "Authorization: Bearer ip_live_your_key_here" | jq .

# Create a monitor
curl -X POST https://indiepulse.dev/api/v1/monitors \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "My API", "url": "https://api.example.com"}'

# Acknowledge an incident
curl -X POST https://indiepulse.dev/api/v1/events/EVENT_ID/acknowledge \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"message": "Investigating — checking recent deploys"}'

# Resolve an incident
curl -X POST https://indiepulse.dev/api/v1/events/EVENT_ID/resolve \
  -H "Authorization: Bearer ip_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"message": "Reverted bad commit, confirmed recovery"}'

JavaScript (fetch)

const headers = {
  'Authorization': 'Bearer ip_live_your_key_here',
  'Content-Type': 'application/json',
};

// List monitors
const res = await fetch('https://indiepulse.dev/api/v1/monitors', { headers });
const { data: monitors } = await res.json();

for (const m of monitors) {
  console.log(`${m.name}: ${m.monitor_state}`);
}

// Create a monitor
const createRes = await fetch('https://indiepulse.dev/api/v1/monitors', {
  method: 'POST',
  headers,
  body: JSON.stringify({
    name: 'My API',
    url: 'https://api.example.com/health',
    check_interval: 300,
  }),
});
const { data: newMonitor } = await createRes.json();
console.log(`Created: ${newMonitor.id}`);

// Acknowledge an incident
await fetch(`https://indiepulse.dev/api/v1/events/${eventId}/acknowledge`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ message: 'On it' }),
});

Python (requests)

import requests

headers = {"Authorization": "Bearer ip_live_your_key_here"}
BASE = "https://indiepulse.dev/api/v1"

# Workspace status
resp = requests.get(f"{BASE}/status", headers=headers)
status = resp.json()["data"]
print(f"Status: {status['overall_status']}")

# Create a monitor
resp = requests.post(f"{BASE}/monitors", headers=headers, json={
    "name": "My API",
    "url": "https://api.example.com/health",
    "check_interval": 300,
})
monitor = resp.json()["data"]
print(f"Created monitor: {monitor['id']}")

# Full incident lifecycle
event_id = "..."
requests.post(f"{BASE}/events/{event_id}/acknowledge", headers=headers,
              json={"message": "Investigating"})
requests.post(f"{BASE}/events/{event_id}/resolve", headers=headers,
              json={"message": "Fixed via rollback"})

Heartbeat Integration

Heartbeat monitors use a dead-man's switch pattern: your job pings IndiePulse on success, and we alert you if the ping doesn't arrive on time. Find your heartbeat URL in the monitor settings page.

crontab

# Ping after successful backup (every day at 2 AM)
0 2 * * * /usr/bin/backup.sh && curl -fsS https://indiepulse.dev/api/v1/heartbeat/YOUR_TOKEN > /dev/null

Node.js

// At the end of your scheduled job
await fetch('https://indiepulse.dev/api/v1/heartbeat/YOUR_TOKEN');

// Signal failure explicitly
await fetch('https://indiepulse.dev/api/v1/heartbeat/YOUR_TOKEN/fail', { method: 'POST' });

Python

import requests

# Success ping
requests.get("https://indiepulse.dev/api/v1/heartbeat/YOUR_TOKEN")

# Failure signal
requests.post("https://indiepulse.dev/api/v1/heartbeat/YOUR_TOKEN/fail")

Webhooks

Configure webhook endpoints in Settings → Notifications to receive real-time JSON payloads when events occur.

Payload Format

{
  "event_type": "incident.created",
  "timestamp": "2026-02-19T15:30:00.000Z",
  "workspace": { "id": "uuid", "name": "My Workspace" },
  "monitor": {
    "id": "uuid",
    "name": "API Server",
    "url": "https://api.example.com",
    "monitor_type": "http"
  },
  "event": {
    "id": "uuid",
    "title": "api.example.com is down",
    "status": "Investigating",
    "created_at": "2026-02-19T15:30:00.000Z",
    "dashboard_url": "https://app.indiepulse.io/monitors/uuid",
    "acknowledge_url": "https://app.indiepulse.io/ack?token=xxx&via=webhook"
  },
  "ai_insight": "High error rate detected across all regions..."
}

Event Types

event_typeDescription
incident.createdA new downtime incident was detected
incident.resolvedAn incident has been resolved
incident.escalatedAn incident was escalated after prolonged duration
performance.createdSustained performance degradation detected
performance.resolvedPerformance returned to normal
digest.weeklyWeekly health digest summary
testTest event sent during webhook setup

Signature Verification

Every webhook includes an X-IndiePulse-Signature header containing an HMAC-SHA256 signature of the raw request body. Always verify this signature to ensure the payload was sent by IndiePulse.

import crypto from 'crypto';

function verifyWebhook(body: string, signature: string, secret: string): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
const isValid = verifyWebhook(rawBody, req.headers['x-indiepulse-signature'], SIGNING_SECRET);
if (!isValid) return res.status(401).send('Invalid signature');

MCP Server

The @indiepulse/mcp package wraps the HTTP API with AI-optimized tool descriptions for Claude, Cursor, Windsurf, and any MCP-compatible client.

Setup

1. Get your API key at Settings → API

2. Add to your MCP client config:

{
  "mcpServers": {
    "indiepulse": {
      "command": "npx",
      "args": ["-y", "@indiepulse/mcp"],
      "env": { "INDIEPULSE_API_KEY": "ip_live_..." }
    }
  }
}

3. Ask Claude: “Check my IndiePulse monitors”

Available Tools

ToolDescription
list_monitorsList all monitors with status and health scores
get_monitorMonitor detail including 24h stats
get_monitor_checksRecent check results and response times
create_monitorCreate new HTTP monitor
update_monitorUpdate monitor configuration
delete_monitorSoft-delete a monitor
pause_monitorPause monitoring (stops checks)
resume_monitorResume a paused monitor
trigger_checkTrigger instant re-check (60s cooldown)
get_workspace_statusOverall workspace health summary
list_eventsList incidents, performance events, maintenance
get_eventEvent detail with update timeline
acknowledge_eventAcknowledge incident (pauses escalations, 30min window)
update_eventPost status update to incident
resolve_eventResolve incident with message
create_eventCreate manual incident or schedule maintenance
start_maintenanceStart a scheduled maintenance window
complete_maintenanceComplete maintenance
cancel_maintenanceCancel scheduled maintenance

Resources & Prompts

Resources (auto-refreshing data):

  • indiepulse://status — Live workspace status
  • indiepulse://monitors — Monitor list with current state

Prompts (pre-built workflows):

  • investigate — Guided incident triage and diagnosis
  • analyze — Monitor health analysis

Agent Patterns

Auto-Remediation Loop

The killer workflow. Your CI/CD pipeline deploys. IndiePulse detects the site is down. A webhook fires. Your agent:

  1. Acknowledges the incident — pauses escalations (30min window to resolve before humans get paged)
  2. Queries checks endpoint — sees 502 errors in US-East and EU
  3. Queries GitHub for recent commits — finds the deploy 3 minutes ago
  4. Creates a revert commit and pushes
  5. Triggers an instant check — waits for deploy, then verifies
  6. Resolves the incident — with a summary of what happened
  7. Posts to Slack — “Incident auto-resolved in 90 seconds”

Total time: 90 seconds. You slept through it.

Webhook + MCP Flow

// 1. Webhook handler receives incident.created
app.post('/webhook/indiepulse', async (req, res) => {
  const { event_type, event } = req.body;

  if (event_type === 'incident.created') {
    // 2. Acknowledge via API (pauses escalations — 30min window)
    await fetch(`https://indiepulse.dev/api/v1/events/${event.id}/acknowledge`, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({ message: 'Auto-agent investigating' }),
    });

    // 3. Get diagnostics
    const checks = await fetch(
      `https://indiepulse.dev/api/v1/monitors/${event.monitor_id}/checks`,
      { headers: { 'Authorization': `Bearer ${API_KEY}` } }
    ).then(r => r.json());

    // 4. Your remediation logic here...

    // 5. Verify fix
    await fetch(`https://indiepulse.dev/api/v1/monitors/${event.monitor_id}/check`, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${API_KEY}` },
    });

    // 6. Resolve
    await fetch(`https://indiepulse.dev/api/v1/events/${event.id}/resolve`, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({ message: 'Auto-resolved: reverted bad deploy' }),
    });
  }

  res.sendStatus(200);
});

Every API action records the API key name in the audit trail, so you can see exactly what your agent did in the incident timeline.

Error Responses

All errors return a JSON object with an error field containing code and message.

StatusMeaningExample
400Invalid request body or parameters{"error":{"code":"MISSING_URL","message":"url is required"}}
401Invalid or missing API key{"error":{"code":"UNAUTHORIZED","message":"Invalid API key"}}
403Incident resolution requires paid plan{"error":{"code":"INCIDENT_WRITE_ACCESS_REQUIRED","message":"..."}}
404Resource not found{"error":{"code":"NOT_FOUND","message":"Monitor not found"}}
409Conflict (already paused, already resolved){"error":{"code":"CONFLICT","message":"Monitor is already paused"}}
429Rate limit exceeded{"error":{"code":"RATE_LIMITED","message":"Rate limit exceeded"}}

Ready to start?

Generate your API key and start building integrations — or set up MCP for your AI agent.