Documentation
Start monitoring your cron jobs in under 2 minutes.
Quick Start
Create a monitor
Go to your dashboard and click "New Monitor". Give it a name, pick how often it should be pinged, and set a grace period.
Add a ping to your job
At the end of your cron job or script, add an HTTP request to your monitor's unique ping URL.
# Add this at the end of your cron job
curl -fsS --retry 3 https://pulsemon.dev/api/ping/your-slugGet alerted
If your job misses a ping, PulseMon detects it within 60 seconds and sends you an alert via email, Slack, Discord, or webhook.
How Monitoring Works
PulseMon uses a dead-man's-switch model. Your job pings us on success; if we don't hear from it in time, we alert you.
last ping + interval + grace period. If no ping arrives before the deadline, the monitor is marked down.Alert escalation: When a monitor goes down you receive an immediate alert, then follow-up reminders at 1 h, 6 h, and 24 h. After that, reminders repeat daily until the monitor recovers.
Ping API
Send a heartbeat ping for the given monitor. Always returns 200 OK, even on internal errors, so your cron job won't fail because of monitoring.
Parameters
slugstringMonitor slug (path param)status"success" | "fail"Optional. Report a failure explicitlydurationnumberOptional. Job duration in msResponse
{ "ok": true }Same as GET, but accepts a JSON body for additional metadata.
Body Parameters
status"success" | "fail"Optional. Defaults to "success"durationnumberOptional. Job duration in msbodystringOptional. Job output or error message (max 10 KB)curl -X POST https://pulsemon.dev/api/ping/your-slug \
-H "Content-Type: application/json" \
-d '{"status": "success", "duration": 1234, "body": "Processed 500 records"}'Reporting Failures
By default, every ping is treated as a success and resets the monitor's deadline. If your job detects an error, you can report it explicitly with ?status=fail.
A fail ping immediately marks the monitor as down, creates an incident, and fires an alert. It does not reset the deadline. The monitor recovers when the next success ping arrives.
If you include a body with the fail ping, the error output will be included in the alert so you can see what went wrong without checking the server.
#!/bin/bash
set -e
if /usr/local/bin/backup.sh; then
curl -fsS --retry 3 "https://pulsemon.dev/api/ping/nightly-backup"
else
curl -fsS --retry 3 "https://pulsemon.dev/api/ping/nightly-backup?status=fail"
fiSending Job Output
Attach your job's stdout, stderr, or a summary to the ping. When PulseMon fires an alert, the output is included so you can see why a job failed without SSHing into the server.
Send output as the body field in a POST request. Up to 10 KB. The body is shown in your ping history and included in all alert notifications (email, Slack, Discord, and webhooks).
Pipe script output
#!/bin/bash
set -e
# Capture output and exit code
OUTPUT=$(./backup.sh 2>&1) || STATUS="fail"
# Send the output with the ping
curl -fsS --retry 3 -X POST https://pulsemon.dev/api/ping/nightly-backup \
-H "Content-Type: application/json" \
-d "$(jq -n --arg body "$OUTPUT" --arg status "${STATUS:-success}" \
'{status: $status, body: $body}')"Send structured data
import requests, time, json
start = time.time()
result = process_records()
duration = int((time.time() - start) * 1000)
requests.post(
"https://pulsemon.dev/api/ping/record-processor",
json={
"duration": duration,
"body": json.dumps({
"rows_processed": result.count,
"errors": result.errors,
"source": "warehouse-db",
}),
},
timeout=10,
)If the body is valid JSON, PulseMon pretty-prints it in the dashboard with syntax highlighting. Plain text is shown in a monospace code block.
Duration Thresholds
Get alerted when a job completes but takes longer than expected.
Set a max duration on any monitor (under Advanced Settings). If a ping reports a duration that exceeds the threshold, PulseMon fires a [SLOW] alert and opens an incident. When the next ping comes in under the threshold, the incident auto-resolves.
# Report duration so PulseMon can check against your threshold
START=$(date +%s%3N)
./etl-pipeline.sh
END=$(date +%s%3N)
DURATION=$((END - START))
curl -fsS --retry 3 "https://pulsemon.dev/api/ping/etl-pipeline?duration=$DURATION"Duration is in milliseconds. For example, set the max to 300 seconds (5 minutes) in the dashboard, then pass duration=360000 to trigger a slow alert.
Start Signal & Overlap Detection
Detect when a job starts a new run before the previous one finishes.
Send a ?status=start ping when your job begins. PulseMon tracks whether the job is currently running. If a second start ping arrives before a success or fail ping, PulseMon fires an [OVERLAP] alert.
Example usage
#!/bin/bash
set -e
# Signal start
curl -fsS https://pulsemon.dev/api/ping/nightly-backup?status=start
# Run the job
/usr/local/bin/backup.sh
# Signal completion
curl -fsS https://pulsemon.dev/api/ping/nightly-backupStart pings do not reset the deadline. Only success pings reset the deadline and mark the monitor as up.
Rate Limiting
The ping endpoint enforces a rate limit of 1 request per second per slug per status. The bucket is separate for start, success, and fail pings, so a normal start → success lifecycle never rate-limits itself. If you exceed the limit, the endpoint returns a 429 status code.
// 429 response
{ "ok": false, "error": "Rate limited" }This prevents accidental flood loops. Any real cron job or heartbeat stays well under 1 req/sec. If you use curl --retry 3, retries will back off naturally and won't hit this limit.
Integration Examples
# Run backup every day at 2am, ping PulseMon on success
0 2 * * * /usr/local/bin/backup.sh && curl -fsS --retry 3 https://pulsemon.dev/api/ping/nightly-backupAlert Channels
Webhook Payload
When an alert fires, PulseMon sends a JSON POST request with this payload:
{
"event": "monitor.down",
"monitor": {
"id": "uuid",
"name": "Nightly Backup",
"slug": "nightly-backup",
"status": "down",
"lastPingAt": "2025-01-15T02:00:00Z",
"expectedInterval": 86400,
"lastPingBody": "pg_dump: error: connection refused"
},
"incident": {
"id": "uuid",
"startedAt": "2025-01-16T02:05:00Z"
},
"timestamp": "2025-01-16T02:05:00Z"
}The lastPingBody field contains the output from the most recent ping, if any was sent. It's included in all alert types.
Recovery events use "event": "monitor.up". Slow alerts use "event": "monitor.slow" and include lastPingDuration and maxDuration on the monitor object.
Webhook Signature Verification
If you configure a secret on your webhook alert channel, PulseMon signs every request with an HMAC-SHA256 signature in the X-PulseMon-Signature header. The format is sha256=<hex>. Verify this before processing the payload.
import crypto from "crypto";
function verifySignature(body, secret, signatureHeader) {
const expected = "sha256=" +
crypto.createHmac("sha256", secret).update(body).digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader),
);
}
// In your webhook handler:
app.post("/webhooks/pulsemon", (req, res) => {
const signature = req.headers["x-pulsemon-signature"];
const body = JSON.stringify(req.body);
if (!signature || !verifySignature(body, process.env.WEBHOOK_SECRET, signature)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = req.body;
console.log(`Monitor ${event.monitor.name} is ${event.event}`);
res.json({ ok: true });
});API Keys
Create API keys in Settings → API Keys to manage monitors programmatically. Keys use Bearer token auth with the prefix pm_. You only see the raw key once at creation, so store it somewhere safe.
Authentication
curl https://pulsemon.dev/api/v1/monitors \
-H "Authorization: Bearer pm_your-api-key"Endpoints
/api/v1/monitorsList all monitors/api/v1/monitorsCreate a monitor/api/v1/monitors/{id}Get monitor details/api/v1/monitors/{id}Update a monitor/api/v1/monitors/{id}Delete a monitor/api/v1/monitors/{id}/pausePause a monitor/api/v1/monitors/{id}/resumeResume a monitor/api/v1/monitors/{id}/pingsPing history (paginated)/api/v1/monitors/{id}/incidentsIncident history (paginated)Example: Create a Monitor
curl -X POST https://pulsemon.dev/api/v1/monitors \
-H "Authorization: Bearer pm_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly Backup",
"slug": "nightly-backup",
"expectedInterval": 86400,
"gracePeriod": 900
}'All endpoints return { "data": T, "error": null } on success and { "data": null, "error": { "code": "...", "message": "..." } } on failure. Missing or invalid keys return 401.
OpenClaw Skill
Use PulseMon from WhatsApp, Telegram, or Slack via OpenClaw. Install the skill and manage your monitors with natural language.
clawhub install pulsemonSet your API key as an environment variable:
PULSEMON_API_KEY=pm_your-key-hereThen ask your agent things like "check my monitors", "create a monitor called nightly-backup that runs daily", or "pause the data-sync monitor".