Everything you need to integrate CronPulse into your workflow.
The fastest way to use CronPulse is the ping URL. No API key needed — just append it to your cron job:
# Your cron job + CronPulse ping
0 2 * * * /usr/local/bin/backup.sh && curl -fsS https://ping.trebben.dk/YOUR_SLUG
Install the CronPulse wrapper for cleaner crontabs and automatic exit code handling:
# Install
curl -sS https://cronpulse.trebben.dk/cli.sh -o /usr/local/bin/cronpulse && chmod +x /usr/local/bin/cronpulse
# Use in crontab — pings only on success
0 2 * * * cronpulse YOUR_SLUG /usr/local/bin/backup.sh
# Always ping (even on failure)
0 2 * * * cronpulse -a YOUR_SLUG /usr/local/bin/backup.sh
# Just ping (no command)
cronpulse YOUR_SLUG
Parse and explain cron expressions programmatically. No account needed. CORS enabled.
Returns a human-readable description and next run times for any cron expression.
curl "https://cronpulse.trebben.dk/api/cron/explain?expr=0+9+*+*+1-5"
{
"expression": "0 9 * * 1-5",
"description": "At 09:00 on Monday–Friday",
"next_runs": ["2026-03-25T09:00:00.000Z", ...],
"fields": {
"minute": "0", "hour": "9",
"day_of_month": "*", "month": "*", "day_of_week": "1-5"
}
}
Returns next N run times (default 5, max 20).
curl "https://cronpulse.trebben.dk/api/cron/next?expr=*/5+*+*+*+*&n=3"
{
"expression": "*/5 * * * *",
"next_runs": [
"2026-03-24T10:00:00.000Z",
"2026-03-24T10:05:00.000Z",
"2026-03-24T10:10:00.000Z"
]
}
Use these endpoints in CI scripts, documentation, or any tool that needs cron schedule info. No rate limit, no API key, CORS enabled for browser use.
Also available as a Telegram bot — send any cron expression and get an instant explanation.
API requests (except pings and the cron expression API) require authentication via JWT token or API key.
Authorization: Bearer <token>
Get a token from POST /api/auth/login. Tokens expire after 7 days.
X-Api-Key: <your-api-key>
Get your API key from the Settings page. API keys don't expire.
Ping URLs require no authentication. The slug IS the secret.
Record a successful execution. Returns {"ok": true, "status": "ok"}.
# Bash — ping on success only
0 * * * * /path/to/job.sh && curl -fsS https://ping.trebben.dk/SLUG
# Python
import urllib.request
urllib.request.urlopen("https://ping.trebben.dk/SLUG")
# Node.js (with client library)
const cronpulse = require('cronpulse');
await cronpulse('SLUG').ping();
# Node.js (raw fetch)
await fetch("https://ping.trebben.dk/SLUG");
# PowerShell
Invoke-WebRequest -Uri "https://ping.trebben.dk/SLUG" -UseBasicParsing
# wget
wget -q --spider https://ping.trebben.dk/SLUG
For Node.js applications, use the official client library for cleaner integration:
npm install cronpulse
const cronpulse = require('cronpulse');
const monitor = cronpulse('your-slug');
// At the end of your job
await monitor.ping();
const cronpulse = require('cronpulse');
const monitor = cronpulse('nightly-cleanup');
await monitor.wrap(async () => {
await db.query('DELETE FROM sessions WHERE expired_at < NOW()');
});
If the wrapped function throws, no ping is sent — CronPulse will detect the missed heartbeat and alert you.
CronPulse works anywhere you can make an HTTP request. Here are copy-paste examples for common platforms.
Healthcheck pattern — ping CronPulse after your container's task completes:
# Dockerfile
FROM alpine:3.19
RUN apk add --no-cache curl
COPY backup.sh /backup.sh
CMD /backup.sh && curl -fsS https://ping.trebben.dk/SLUG
Or wrap an existing container in docker-compose:
# docker-compose.yml
services:
backup:
image: your-backup-image
command: sh -c "/backup.sh && curl -fsS https://ping.trebben.dk/SLUG"
# Runs every 6 hours via restart policy + sleep, or use Ofelia/supercronic
Monitor scheduled workflows:
# .github/workflows/nightly.yml
name: Nightly build
on:
schedule:
- cron: '0 2 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make build
- run: make test
- name: Ping CronPulse
if: success()
run: curl -fsS https://ping.trebben.dk/SLUG
Add CronPulse as a sidecar step or final command:
# k8s-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 */6 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: your-backup-image
command: ["/bin/sh", "-c"]
args: ["/backup.sh && curl -fsS https://ping.trebben.dk/SLUG"]
restartPolicy: OnFailure
For systemd-managed scheduled tasks (the modern alternative to cron):
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
ExecStartPost=/usr/bin/curl -fsS https://ping.trebben.dk/SLUG
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup nightly
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
The ExecStartPost directive only runs if ExecStart succeeds — exactly the behavior you want.
# GitLab CI — ping after successful deploy
deploy:
stage: deploy
script:
- ./deploy.sh
- curl -fsS https://ping.trebben.dk/SLUG
# Jenkins Pipeline
stage('Deploy') {
steps {
sh './deploy.sh'
sh 'curl -fsS https://ping.trebben.dk/SLUG'
}
}
// app/Console/Kernel.php
$schedule->command('reports:generate')
->daily()
->after(function () {
Http::get('https://ping.trebben.dk/SLUG');
});
| Field | Type | Required |
|---|---|---|
| string | Yes | |
| password | string (min 8 chars) | Yes |
Returns: { token, api_key, user_id }
| Field | Type | Required |
|---|---|---|
| string | Yes | |
| password | string | Yes |
Returns: { token, api_key, user_id }
List all monitors for the authenticated user.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Monitor name (max 100 chars) |
| period_seconds | integer | Yes | Expected ping interval (60–31536000) |
| grace_seconds | integer | No | Extra time before alerting (default: 20% of period) |
Returns the created monitor with its ping_url.
Get monitor details including recent pings and alerts. :id accepts numeric ID or slug.
Update monitor name, period, or grace period. :id accepts numeric ID or slug.
Delete a monitor and all its ping/alert history. :id accepts numeric ID or slug.
Pause a monitor (stops alerting). Pings are still accepted but won't reset the deadline.
Resume a paused monitor. Waits for the next ping to re-arm.
Recent alerts across all monitors (last 50).
List notification channels (email, webhook, telegram).
| Field | Type | Description |
|---|---|---|
| channel_type | "email" | "slack" | "webhook" | "telegram" | Alert delivery method |
| target | string | Email address, webhook URL (HTTPS), or Telegram chat ID |
Remove a notification channel.
Returns: { email, api_key, plan, monitor_count, monitor_limit }
Generate a new API key. The old key is immediately invalidated.
| Endpoint | Limit |
|---|---|
| Ping | 1 per second per slug |
| Auth (signup/login) | 10 per 15 minutes per IP |
| API | 60 per minute per user |
CronPulse is a single Node.js process backed by SQLite. No Redis, no message queues, no microservices. The entire application is ~1700 lines of code.
How monitoring works:
https://ping.trebben.dk/:slug. We record the timestamp and reset the monitor's deadline to now + grace_period.next_alert_at < now. Any monitor past its deadline is marked down.down, alerts fire to all configured channels (email, Slack, webhook, Telegram) in parallel. Recovery alerts fire when the next ping arrives.The stack:
The design philosophy: a cron monitoring service should be simpler than the cron jobs it monitors. If you can hold the entire system in your head, you can debug it at 3am. That's the point.
Check any monitor's status by slug. No authentication required — the slug is the secret (same as pings).
Returns JSON with the monitor's current status, last ping time, period, and whether it's overdue.
curl https://cronpulse.trebben.dk/api/monitors/YOUR_SLUG/status
{
"name": "Nightly Backup",
"status": "up",
"last_ping": "2026-03-24T02:00:05.000Z",
"period_seconds": 86400,
"seconds_overdue": 0,
"badge_url": "https://cronpulse.trebben.dk/badge/YOUR_SLUG.svg"
}
Use this to build custom status pages, integrate with Slack bots, or check monitor health in scripts.
Embed a live status badge in your README or dashboard. No authentication required — the slug is the secret (same as pings).
Returns an SVG badge showing the monitor's current status. Wrap it in a link so viewers can click through to CronPulse:
# Markdown (clickable — links back to CronPulse)
[](https://cronpulse.trebben.dk)
# HTML (clickable)
<a href="https://cronpulse.trebben.dk"><img src="https://cronpulse.trebben.dk/badge/YOUR_SLUG.svg" alt="Backup Status"></a>
Badge colors: green = up, red = down, orange = paused, gray = new.
Badges are never cached, so they always reflect the current status.
A generic "monitored by CronPulse" badge. No account needed — add it to any project README:
# Markdown
[](https://cronpulse.trebben.dk)
# HTML
<a href="https://cronpulse.trebben.dk"><img src="https://cronpulse.trebben.dk/badge/cronpulse.svg" alt="Monitored by CronPulse"></a>
Built by Jeff in Denmark. Back to CronPulse · Free Developer Tools