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.
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.
| Plan | Access | Per Minute | Per Day | Max Keys |
|---|---|---|---|---|
| Free | Read + Ack | 10 | 500 | 1 |
| Hacker | Full | 60 | 5,000 | 2 |
| Maker | Full | 120 | 20,000 | 5 |
| Founder | Full | 300 | 100,000 | 10 |
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.
| Field | Purpose | Values |
|---|---|---|
| status | Latest consensus check result | UP, DOWN, DEGRADED |
| monitor_state | Operational state machine | PENDING, 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:
Only INCIDENT events reduce uptime. PERFORMANCE degradations do not. Returns null when no check data exists.
Event Types
| Type | Meaning | Affects Uptime? |
|---|---|---|
| INCIDENT | Confirmed downtime | Yes |
| PERFORMANCE | Sustained slow responses | No |
| MAINTENANCE | Scheduled maintenance window | No |
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/:token
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/fail
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_type | Description |
|---|---|
| incident.created | A new downtime incident was detected |
| incident.resolved | An incident has been resolved |
| incident.escalated | An incident was escalated after prolonged duration |
| performance.created | Sustained performance degradation detected |
| performance.resolved | Performance returned to normal |
| digest.weekly | Weekly health digest summary |
| test | Test 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
| Tool | Description |
|---|---|
| list_monitors | List all monitors with status and health scores |
| get_monitor | Monitor detail including 24h stats |
| get_monitor_checks | Recent check results and response times |
| create_monitor | Create new HTTP monitor |
| update_monitor | Update monitor configuration |
| delete_monitor | Soft-delete a monitor |
| pause_monitor | Pause monitoring (stops checks) |
| resume_monitor | Resume a paused monitor |
| trigger_check | Trigger instant re-check (60s cooldown) |
| get_workspace_status | Overall workspace health summary |
| list_events | List incidents, performance events, maintenance |
| get_event | Event detail with update timeline |
| acknowledge_event | Acknowledge incident (pauses escalations, 30min window) |
| update_event | Post status update to incident |
| resolve_event | Resolve incident with message |
| create_event | Create manual incident or schedule maintenance |
| start_maintenance | Start a scheduled maintenance window |
| complete_maintenance | Complete maintenance |
| cancel_maintenance | Cancel scheduled maintenance |
Resources & Prompts
Resources (auto-refreshing data):
indiepulse://status— Live workspace statusindiepulse://monitors— Monitor list with current state
Prompts (pre-built workflows):
investigate— Guided incident triage and diagnosisanalyze— 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:
- Acknowledges the incident — pauses escalations (30min window to resolve before humans get paged)
- Queries checks endpoint — sees 502 errors in US-East and EU
- Queries GitHub for recent commits — finds the deploy 3 minutes ago
- Creates a revert commit and pushes
- Triggers an instant check — waits for deploy, then verifies
- Resolves the incident — with a summary of what happened
- 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.
| Status | Meaning | Example |
|---|---|---|
| 400 | Invalid request body or parameters | {"error":{"code":"MISSING_URL","message":"url is required"}} |
| 401 | Invalid or missing API key | {"error":{"code":"UNAUTHORIZED","message":"Invalid API key"}} |
| 403 | Incident resolution requires paid plan | {"error":{"code":"INCIDENT_WRITE_ACCESS_REQUIRED","message":"..."}} |
| 404 | Resource not found | {"error":{"code":"NOT_FOUND","message":"Monitor not found"}} |
| 409 | Conflict (already paused, already resolved) | {"error":{"code":"CONFLICT","message":"Monitor is already paused"}} |
| 429 | Rate 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.