Everything you need to monitor your cron jobs, scheduled tasks, and background workers with CronPeek.
Get from zero to monitoring in under 60 seconds. Three API calls is all it takes.
Sign up with your email to get a free API key. No credit card required.
curl -X POST "https://cronpeek.web.app/api/v1/accounts" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'
Tell CronPeek what to watch. Set the expected interval in seconds between pings.
curl -X POST "https://cronpeek.web.app/api/v1/monitors" \
-H "x-api-key: cpk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "Nightly DB Backup", "schedule": 86400}'
Add a single line to the end of your script. If the ping stops arriving, CronPeek alerts you.
# Add to the end of your cron script
curl -s "https://cronpeek.web.app/api/v1/ping/YOUR_PING_TOKEN"
https://cronpeek.web.app
All API endpoints are under /api/v1/. All requests and responses use JSON (except ping endpoints which also accept GET/HEAD with no body).
Most endpoints require your API key in the x-api-key header. You get a key when you create an account.
curl -H "x-api-key: cpk_your_key_here" "https://cronpeek.web.app/api/v1/monitors"
Key format: API keys start with cpk_ followed by a 32-character hex string.
No auth required: Account creation and ping endpoints do not require the x-api-key header. Ping endpoints authenticate via their unique token in the URL.
Create a free account and receive your API key. If an account already exists for the email, the existing key is returned.
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Valid email address |
curl -X POST "https://cronpeek.web.app/api/v1/accounts" \
-H "Content-Type: application/json" \
-d '{"email": "dev@company.com"}'
{
"apiKey": "cpk_a1b2c3d4e5f6...",
"plan": "free",
"monitors": 5
}
Create a new monitor. You'll receive a unique ping URL that your cron job should hit on each successful run.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Human-readable name for this monitor |
| schedule | integer | Yes | Expected seconds between pings (min: 60) |
| grace | integer | No | Grace period in seconds before alerting. Defaults to 10% of schedule (min: 60s) |
| alertEmail | string | No | Override alert email (defaults to account email) |
| alertWebhook | string | No | Webhook URL to POST when monitor goes down |
| Interval | Seconds |
|---|---|
| Every minute | 60 |
| Every 5 minutes | 300 |
| Every hour | 3600 |
| Every day | 86400 |
| Every week | 604800 |
curl -X POST "https://cronpeek.web.app/api/v1/monitors" \
-H "x-api-key: cpk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly DB Backup",
"schedule": 86400,
"grace": 3600,
"alertWebhook": "https://hooks.slack.com/services/T00/B00/xxx"
}'
{
"monitorId": "a1b2c3d4e5f67890",
"name": "Nightly DB Backup",
"pingUrl": "https://cronpeek.web.app/api/v1/ping/abc123def456...",
"schedule": 86400,
"grace": 3600,
"status": "new"
}
Save the pingUrl -- this is the URL your cron job will call to report success.
List all monitors for your account, ordered by creation date (newest first).
curl -H "x-api-key: cpk_your_key_here" \
"https://cronpeek.web.app/api/v1/monitors"
{
"monitors": [
{
"monitorId": "a1b2c3d4e5f67890",
"name": "Nightly DB Backup",
"status": "up",
"schedule": 86400,
"grace": 3600,
"lastPing": "2026-03-28T02:00:12.000Z",
"pingCount": 47
}
],
"count": 1
}
| Status | Meaning |
|---|---|
| new | Monitor created, waiting for the first ping |
| up | Pings arriving on schedule |
| down | Ping missed -- schedule + grace period exceeded |
| paused | Monitoring paused (no alerts) |
Get detailed status for a single monitor, including last ping and last alert timestamps.
curl -H "x-api-key: cpk_your_key_here" \
"https://cronpeek.web.app/api/v1/monitors/a1b2c3d4e5f67890/status"
{
"monitorId": "a1b2c3d4e5f67890",
"name": "Nightly DB Backup",
"status": "up",
"schedule": 86400,
"grace": 3600,
"lastPing": "2026-03-28T02:00:12.000Z",
"lastAlert": null,
"pingCount": 47
}
Permanently delete a monitor. This frees up one slot in your monitor limit.
curl -X DELETE \
-H "x-api-key: cpk_your_key_here" \
"https://cronpeek.web.app/api/v1/monitors/a1b2c3d4e5f67890"
{
"deleted": true
}
Report a successful job run. Accepts GET, POST, or HEAD requests. The token is provided in the pingUrl when you create a monitor. No API key needed -- the token itself authenticates the ping.
# GET (simplest -- works from a browser or curl one-liner)
curl "https://cronpeek.web.app/api/v1/ping/abc123def456..."
# HEAD (minimal -- no response body, lowest bandwidth)
curl -I "https://cronpeek.web.app/api/v1/ping/abc123def456..."
# POST (useful if your HTTP client defaults to POST)
curl -X POST "https://cronpeek.web.app/api/v1/ping/abc123def456..."
{
"ok": true,
"monitor": "Nightly DB Backup",
"status": "up"
}
HEAD requests return 200 with no body.
Check if the CronPeek API is online. Useful for your own monitoring or status pages.
curl "https://cronpeek.web.app/api/health"
{
"status": "ok",
"service": "cronpeek",
"version": "1.0.0",
"timestamp": "2026-03-28T12:00:00.000Z"
}
Add CronPeek to any scheduled task that can make an HTTP request. Below are copy-paste examples for common setups.
# Run backup every night at 2 AM, ping CronPeek on success
0 2 * * * /usr/local/bin/backup.sh && curl -s "https://cronpeek.web.app/api/v1/ping/YOUR_TOKEN"
#!/bin/bash
# Your job logic here
/usr/local/bin/process-data.sh
# Ping CronPeek on success (fire-and-forget)
curl -fsS --retry 3 --max-time 10 \
"https://cronpeek.web.app/api/v1/ping/YOUR_TOKEN"
const https = require('https');
async function pingCronPeek(token) {
return new Promise((resolve) => {
https.get(
`https://cronpeek.web.app/api/v1/ping/${token}`,
(res) => resolve(res.statusCode)
).on('error', () => resolve(null));
});
}
// Usage: call after your job completes
await pingCronPeek('YOUR_TOKEN');
import requests
def ping_cronpeek(token):
try:
requests.get(
f"https://cronpeek.web.app/api/v1/ping/{token}",
timeout=10
)
except requests.RequestException:
pass # Don't let monitoring failures break your job
# Usage: call after your job completes
ping_cronpeek("YOUR_TOKEN")
const https = require('https');
exports.handler = async (event) => {
// --- Your Lambda logic ---
const result = await doWork();
// --- Ping CronPeek on success ---
await new Promise((resolve) => {
https.get(
"https://cronpeek.web.app/api/v1/ping/YOUR_TOKEN",
resolve
).on('error', resolve);
});
return { statusCode: 200, body: "done" };
};
import subprocess
import requests
def run_etl_pipeline():
# Your ETL / data processing logic
subprocess.run(["python", "etl.py"], check=True)
# Ping CronPeek on success
requests.get(
"https://cronpeek.web.app/api/v1/ping/YOUR_TOKEN",
timeout=10
)
if __name__ == "__main__":
run_etl_pipeline()
# .github/workflows/nightly.yml
name: Nightly Job
on:
schedule:
- cron: '0 2 * * *'
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/process.sh
- name: Ping CronPeek
run: curl -fsS "https://cronpeek.web.app/api/v1/ping/${{ secrets.CRONPEEK_TOKEN }}"
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: myapp:latest
command:
- /bin/sh
- -c
- "/app/backup.sh && curl -s https://cronpeek.web.app/api/v1/ping/$CRONPEEK_TOKEN"
env:
- name: CRONPEEK_TOKEN
valueFrom:
secretKeyRef:
name: cronpeek
key: token
restartPolicy: OnFailure
Simple, flat pricing. No per-monitor fees. No surprises.
Error responses return JSON with an error field:
{
"error": "Monitor limit reached (5). Upgrade your plan for more monitors."
}