Appearance
Programmatic API & MCP Server
Pingward provides two programmatic interfaces beyond the standard REST API: an MCP (Model Context Protocol) server for AI-assisted monitoring management, and a Heartbeat Monitor API for dead-man-switch style monitoring of background jobs and cron tasks.
Together these interfaces let you:
- Manage tests and heartbeat monitors from AI assistants (Claude, GPT, Copilot, etc.)
- Set up monitoring for entire APIs in a single conversation
- Audit your monitoring coverage and get AI-driven recommendations
- Integrate heartbeat pings into cron jobs, CI/CD pipelines, and background workers
MCP Server
Model Context Protocol (MCP) is an open standard that lets AI assistants interact with external tools and data sources. Pingward's MCP server exposes monitoring management tools that any MCP-compatible AI client can use directly.
The MCP server runs as part of the Pingward API and is available at:
https://api.pingward.com/mcpSetup
Claude Desktop
Add the following to your Claude Desktop MCP configuration (claude_desktop_config.json):
json
{
"mcpServers": {
"pingward": {
"url": "https://api.pingward.com/mcp",
"headers": {
"X-Api-Key": "pw_live_your_api_key_here"
}
}
}
}Other MCP Clients
Any MCP-compatible client can connect using HTTP Streamable transport:
- Endpoint:
https://api.pingward.com/mcp - Transport: HTTP (Streamable HTTP)
- Authentication: Pass your API key in the
X-Api-Keyheader
Available Tools
The MCP server exposes the following tools, automatically discovered by AI clients.
Test Management
| Tool | Description | Read-only | Destructive |
|---|---|---|---|
list_tests | List monitoring tests with optional filtering by status, type, tag, or search query | Yes | No |
create_http_test | Create an HTTP endpoint monitoring test | No | No |
create_ssl_test | Create an SSL certificate expiry monitor | No | No |
create_dns_test | Create a DNS record monitor | No | No |
update_test | Update an existing test's configuration | No | No |
delete_test | Permanently delete a monitoring test | No | Yes |
run_test | Execute a test immediately and return results | No | No |
pause_test | Pause a test so it stops executing on schedule | No | No |
resume_test | Resume a paused test | No | No |
get_test_results | Get recent execution results for a test | Yes | No |
Heartbeat Management
| Tool | Description | Read-only | Destructive |
|---|---|---|---|
list_heartbeat_monitors | List all heartbeat (dead-man-switch) monitors with optional status filter | Yes | No |
create_heartbeat_monitor | Create a heartbeat monitor and get a ping URL | No | No |
delete_heartbeat_monitor | Permanently delete a heartbeat monitor | No | Yes |
Infrastructure
| Tool | Description | Read-only | Destructive |
|---|---|---|---|
list_regions | List available monitoring regions and their current status | Yes | No |
Tool Parameters
list_tests
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: Active, Paused, Disabled |
testType | string | Filter by type: Http, McpServer, A2aAgent, GraphQl, Grpc, SslCertificate, DnsRecord |
tag | string | Filter by tag name |
search | string | Search by name or URL |
create_http_test
| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | required | Name for this monitoring test |
url | string | required | URL to monitor (e.g. https://api.example.com/health) |
httpMethod | string | GET | HTTP method: GET, POST, PUT, DELETE, PATCH, HEAD |
frequencyMinutes | int | 5 | Check frequency in minutes (1-1440) |
expectedStatusCode | int | - | Expected HTTP status code. Creates a status code assertion |
maxResponseTimeMs | int | - | Maximum acceptable response time in ms. Creates a response time assertion |
tags | string | - | Comma-separated tags (e.g. production,critical) |
importance | string | Production | Importance level: Production, Staging, Development |
regions | string | * | Comma-separated regions or * for all (e.g. eastus,westeurope) |
create_ssl_test
| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | required | Name for this monitor |
hostname | string | required | Hostname to check (e.g. api.example.com) |
port | int | 443 | Port number |
warningDays | int | 30 | Warn when certificate expires within this many days |
frequencyMinutes | int | 1440 | Check frequency in minutes (default: daily) |
regions | string | * | Comma-separated regions or * |
create_dns_test
| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | required | Name for this monitor |
hostname | string | required | Hostname to check (e.g. api.example.com) |
recordType | string | A | DNS record type: A, AAAA, CNAME, MX, TXT, NS |
expectedValue | string | - | Expected value (e.g. IP address). Leave empty to just verify resolution |
frequencyMinutes | int | 60 | Check frequency in minutes |
regions | string | * | Comma-separated regions or * |
update_test
| Parameter | Type | Description |
|---|---|---|
testId | string | required - The test ID (GUID) to update |
name | string | New name |
url | string | New URL |
frequencyMinutes | int | New frequency in minutes |
importance | string | New importance: Production, Staging, Development |
tags | string | New comma-separated tags |
delete_test
| Parameter | Type | Description |
|---|---|---|
testId | string | required - The test ID (GUID) to delete |
Note: Infrastructure tests cannot be deleted.
run_test
| Parameter | Type | Description |
|---|---|---|
testId | string | required - The test ID (GUID) to execute |
Returns the full execution result including status code, response time, assertion results, and any error details.
pause_test / resume_test
| Parameter | Type | Description |
|---|---|---|
testId | string | required - The test ID (GUID) to pause or resume |
get_test_results
| Parameter | Type | Default | Description |
|---|---|---|---|
testId | string | required | The test ID (GUID) |
limit | int | 10 | Number of results to return (1-100) |
list_heartbeat_monitors
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: Waiting, Healthy, Overdue, Missing |
create_heartbeat_monitor
| Parameter | Type | Default | Description |
|---|---|---|---|
name | string | required | Name for this monitor (e.g. Nightly backup job) |
expectedIntervalMinutes | int | 5 | Expected interval between pings in minutes (1-1440) |
gracePeriodMinutes | int | 5 | Grace period in minutes before alerting (0-60) |
tags | string | - | Tags for categorization |
delete_heartbeat_monitor
| Parameter | Type | Description |
|---|---|---|
monitorId | string | required - The heartbeat monitor ID (GUID) to delete |
Prompts
The MCP server also provides built-in prompts that guide AI assistants through common monitoring workflows.
create_monitoring_for_api
Creates a comprehensive monitoring plan for an API. The AI will:
- Check existing monitoring coverage for the domain
- List available monitoring regions
- Suggest a monitoring plan covering health endpoints, key API endpoints, SSL certificates, and DNS resolution
- Ask for confirmation before creating tests
- Create the tests and verify the result
| Parameter | Type | Description |
|---|---|---|
baseUrl | string | required - The base URL of the API (e.g. https://api.example.com) |
apiDescription | string | Optional description of the API and its critical endpoints |
audit_monitoring
Audits the existing monitoring configuration and suggests improvements. The AI will analyze:
- Coverage gaps: Missing SSL/DNS monitors, single-test domains, no heartbeat monitors for background jobs
- Configuration issues: Single-region tests, missing assertions, inappropriate check intervals
- Status issues: Forgotten paused tests, consistently failing tests
- Best practice compliance
No parameters required.
Heartbeat Monitor API
Heartbeat monitors (also called dead-man-switch monitors) work in reverse compared to regular tests: instead of Pingward reaching out to check your service, your service sends periodic "heartbeat" pings to Pingward. If pings stop arriving within the expected interval plus grace period, an alert is triggered.
Use heartbeat monitors for:
- Cron jobs and scheduled tasks
- Background workers and queue processors
- Nightly backups and data pipelines
- Any process that should run on a regular schedule
Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/heartbeat-monitors | API key / JWT | List all heartbeat monitors |
| GET | /api/heartbeat-monitors/:id | API key / JWT | Get a specific monitor |
| POST | /api/heartbeat-monitors | API key / JWT | Create a new monitor |
| PUT | /api/heartbeat-monitors/:id | API key / JWT | Update a monitor |
| DELETE | /api/heartbeat-monitors/:id | API key / JWT | Delete a monitor |
| POST | /api/heartbeat-monitors/:id/pause | API key / JWT | Pause monitoring |
| POST | /api/heartbeat-monitors/:id/resume | API key / JWT | Resume monitoring |
| GET | /api/heartbeat-monitors/:id/pings | API key / JWT | Get ping history |
| GET | /api/heartbeat-monitors/:id/events | API key / JWT | Get status change events |
| POST/GET | /ping/:pingKey | None (public) | Send a heartbeat ping |
List Heartbeat Monitors
GET /api/heartbeat-monitorsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: Waiting, Healthy, Overdue, Missing |
search | string | Search by name |
limit | number | Results per page (1-200, default 50) |
offset | number | Results to skip |
Response
Without pagination parameters:
json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Nightly backup job",
"pingKey": "abc123def456ghi789...",
"pingUrl": "https://api.pingward.com/ping/abc123def456ghi789...",
"status": "Healthy",
"expectedIntervalMinutes": 1440,
"gracePeriodMinutes": 30,
"lastPingAt": "2025-01-24T03:00:12Z",
"nextExpectedAt": "2025-01-25T03:30:12Z",
"isPaused": false,
"tags": "backup,nightly",
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-24T03:00:12Z"
}
]With limit or offset parameters, the response is paginated:
json
{
"items": [ ... ],
"total": 12,
"limit": 50,
"offset": 0
}Get Heartbeat Monitor
GET /api/heartbeat-monitors/:idReturns a single heartbeat monitor object.
Create Heartbeat Monitor
POST /api/heartbeat-monitors
Content-Type: application/json
{
"name": "Nightly backup job",
"expectedIntervalMinutes": 1440,
"gracePeriodMinutes": 30,
"tags": "backup,nightly"
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Monitor name (1-255 characters) |
expectedIntervalMinutes | number | No | Expected interval between pings (1-1440, default 5) |
gracePeriodMinutes | number | No | Grace period before alert (0-60, default 5) |
tags | string | No | Comma-separated tags |
Response
Returns the created monitor with 201 Created, including the pingKey and pingUrl that your service will use to send pings.
TIP
Heartbeat monitors share the test slot quota with your monitoring tests. Each heartbeat monitor counts as one test slot.
Update Heartbeat Monitor
PUT /api/heartbeat-monitors/:id
Content-Type: application/json
{
"name": "Updated backup job",
"expectedIntervalMinutes": 720,
"gracePeriodMinutes": 15
}Only include fields you want to change. If the interval changes and the monitor has received pings, nextExpectedAt is automatically recalculated.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | New name (1-255 characters) |
expectedIntervalMinutes | number | No | New expected interval (1-1440) |
gracePeriodMinutes | number | No | New grace period (0-60) |
tags | string | No | New tags |
Delete Heartbeat Monitor
DELETE /api/heartbeat-monitors/:idReturns 204 No Content on success.
Pause / Resume Heartbeat Monitor
Pause monitoring to suppress alerts during planned downtime:
POST /api/heartbeat-monitors/:id/pause
POST /api/heartbeat-monitors/:id/resumeWhen resumed, nextExpectedAt is recalculated from the current time to avoid an immediate overdue alert.
Get Ping History
GET /api/heartbeat-monitors/:id/pings?limit=50&offset=0Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Number of pings to return |
offset | number | 0 | Pings to skip |
Response
json
[
{
"id": "...",
"receivedAt": "2025-01-24T03:00:12Z",
"payload": "backup completed: 1.2GB, 342 tables",
"sourceIp": "203.0.113.42",
"userAgent": "curl/8.4.0"
}
]Get Events
GET /api/heartbeat-monitors/:id/events?limit=50&offset=0Returns status change events for the monitor.
Response
json
[
{
"id": "...",
"eventType": "StatusChanged",
"fromStatus": "Waiting",
"toStatus": "Healthy",
"occurredAt": "2025-01-24T03:00:12Z",
"details": "First ping received"
}
]Event types: Created, StatusChanged, Paused, Resumed.
Send Heartbeat Ping
This is the public endpoint your services call to report they are alive. No authentication is required -- the unique pingKey in the URL identifies the monitor.
POST /ping/:pingKey
GET /ping/:pingKeyBoth GET and POST are supported, making it easy to integrate with any tool:
bash
# Simple GET request (e.g., from cron)
curl https://api.pingward.com/ping/abc123def456ghi789
# POST with optional payload
curl -X POST https://api.pingward.com/ping/abc123def456ghi789 \
-H "Content-Type: application/json" \
-d '{"payload": "backup completed: 1.2GB, 342 tables"}'Optional Request Body (POST only)
| Field | Type | Description |
|---|---|---|
payload | string | Optional payload to include with the ping (e.g., job status, metrics) |
Response
json
{
"status": "ok",
"receivedAt": "2025-01-24T03:00:12Z",
"monitorName": "Nightly backup job"
}If the monitor is paused, the status will be "paused" but the ping is still recorded.
Heartbeat Status Lifecycle
| Status | Meaning |
|---|---|
Waiting | Monitor created, no ping received yet |
Healthy | Pings arriving within the expected interval |
Overdue | No ping received within interval + grace period |
Missing | Extended period without pings (alert triggered) |
When a ping is received, the monitor transitions to Healthy regardless of its previous state.
Authentication
MCP Server
The MCP server uses the same authentication as the REST API. Pass your API key in the X-Api-Key header when connecting:
X-Api-Key: pw_live_your_api_key_hereThe MCP server inherits the workspace context from the API key, so all operations are scoped to the workspace that owns the key.
Heartbeat Monitor REST API
The CRUD endpoints under /api/heartbeat-monitors require authentication via API key or JWT token, just like other REST API endpoints.
API key scopes required:
| Operation | Required Scope |
|---|---|
| List / Get monitors | read |
| Create / Update / Pause / Resume | write |
| Delete | delete |
| Get pings / events | read |
Heartbeat Ping Endpoint
The /ping/:pingKey endpoint is public and requires no authentication. The unique pingKey (a 32-character URL-safe token generated when the monitor is created) serves as the identifier. Keep your ping keys secret -- anyone with the key can send pings.
Rate Limits
| Endpoint | Limit |
|---|---|
MCP server (/mcp) | 100 requests/min per IP (global) |
REST API (/api/heartbeat-monitors) | 300 requests/min per tenant |
Ping endpoint (/ping/:pingKey) | 30 requests/min per IP |
Examples
Set up monitoring with AI (MCP)
Connect your MCP client and ask:
"Set up monitoring for https://api.example.com -- it has /health, /api/users, and /api/orders endpoints"
The AI assistant will use the create_monitoring_for_api prompt to:
- Check for existing monitors on that domain
- List available regions
- Propose HTTP tests, SSL monitoring, and DNS monitoring
- Create everything after your confirmation
Audit monitoring coverage (MCP)
"Audit my monitoring setup and find any gaps"
The AI will use the audit_monitoring prompt to analyze your tests and heartbeat monitors, then provide prioritized recommendations.
Create a heartbeat monitor via REST API
bash
# Create monitor
curl -X POST https://api.pingward.com/api/heartbeat-monitors \
-H "X-Api-Key: pw_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly database backup",
"expectedIntervalMinutes": 1440,
"gracePeriodMinutes": 30,
"tags": "backup,database"
}'Response:
json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Nightly database backup",
"pingKey": "xR7kM2pQ9vW4nL...",
"pingUrl": "https://api.pingward.com/ping/xR7kM2pQ9vW4nL...",
"status": "Waiting",
"expectedIntervalMinutes": 1440,
"gracePeriodMinutes": 30,
"lastPingAt": null,
"nextExpectedAt": null,
"isPaused": false,
"tags": "backup,database",
"createdAt": "2025-01-24T00:00:00Z",
"updatedAt": "2025-01-24T00:00:00Z"
}Integrate heartbeat pings
Cron job (Linux)
bash
# /etc/cron.d/backup-heartbeat
0 3 * * * root /usr/local/bin/run-backup.sh && curl -s https://api.pingward.com/ping/xR7kM2pQ9vW4nL...Scheduled task (Windows PowerShell)
powershell
# Run after backup script completes
& .\Run-Backup.ps1
Invoke-WebRequest -Uri "https://api.pingward.com/ping/xR7kM2pQ9vW4nL..."Python script
python
import requests
def run_data_pipeline():
# ... your pipeline logic ...
pass
if __name__ == "__main__":
run_data_pipeline()
# Report success to Pingward
requests.post(
"https://api.pingward.com/ping/xR7kM2pQ9vW4nL...",
json={"payload": "Pipeline completed: 1,234 records processed"}
)Node.js worker
javascript
async function processQueue() {
// ... your queue processing logic ...
}
// After successful processing, send heartbeat
await fetch('https://api.pingward.com/ping/xR7kM2pQ9vW4nL...', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payload: 'Queue processed: 42 messages' })
});GitHub Actions workflow
yaml
- name: Deploy
run: ./deploy.sh
- name: Report heartbeat
if: success()
run: curl -s https://api.pingward.com/ping/xR7kM2pQ9vW4nL...List heartbeat monitors with filtering
bash
# List all overdue monitors
curl -H "X-Api-Key: pw_live_abc123..." \
"https://api.pingward.com/api/heartbeat-monitors?status=Overdue"
# Search by name with pagination
curl -H "X-Api-Key: pw_live_abc123..." \
"https://api.pingward.com/api/heartbeat-monitors?search=backup&limit=10&offset=0"Check ping history
bash
curl -H "X-Api-Key: pw_live_abc123..." \
"https://api.pingward.com/api/heartbeat-monitors/550e8400-.../pings?limit=10"