← CronPulse

API Documentation

Everything you need to integrate CronPulse into your workflow.

Quick Start

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

Shell Wrapper (recommended)

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

Cron Expression API (Free, No Auth)

Parse and explain cron expressions programmatically. No account needed. CORS enabled.

GET /api/cron/explain?expr=EXPRESSION

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"
  }
}

GET /api/cron/next?expr=EXPRESSION&n=N

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.

Authentication

API requests (except pings and the cron expression API) require authentication via JWT token or API key.

JWT Token

Authorization: Bearer <token>

Get a token from POST /api/auth/login. Tokens expire after 7 days.

API Key

X-Api-Key: <your-api-key>

Get your API key from the Settings page. API keys don't expire.

Ping Endpoint

Ping URLs require no authentication. The slug IS the secret.

GETPOSTHEAD https://ping.trebben.dk/:slug

Record a successful execution. Returns {"ok": true, "status": "ok"}.

Integration examples

# 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

Node.js Client Library

For Node.js applications, use the official client library for cleaner integration:

npm install cronpulse

Basic ping

const cronpulse = require('cronpulse');
const monitor = cronpulse('your-slug');

// At the end of your job
await monitor.ping();

Wrap your job (ping only on success)

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.

Platform Integrations

CronPulse works anywhere you can make an HTTP request. Here are copy-paste examples for common platforms.

Docker / Docker Compose

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

GitHub Actions

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

Kubernetes CronJobs

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

systemd Timers

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.

CI/CD Pipelines

# 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'
  }
}

Laravel / PHP

// app/Console/Kernel.php
$schedule->command('reports:generate')
    ->daily()
    ->after(function () {
        Http::get('https://ping.trebben.dk/SLUG');
    });

Auth Endpoints

POST /api/auth/signup

FieldTypeRequired
emailstringYes
passwordstring (min 8 chars)Yes

Returns: { token, api_key, user_id }

POST /api/auth/login

FieldTypeRequired
emailstringYes
passwordstringYes

Returns: { token, api_key, user_id }

Monitors

GET /api/monitors

List all monitors for the authenticated user.

POST /api/monitors

FieldTypeRequiredDescription
namestringYesMonitor name (max 100 chars)
period_secondsintegerYesExpected ping interval (60–31536000)
grace_secondsintegerNoExtra time before alerting (default: 20% of period)

Returns the created monitor with its ping_url.

GET /api/monitors/:id

Get monitor details including recent pings and alerts. :id accepts numeric ID or slug.

PUT /api/monitors/:id

Update monitor name, period, or grace period. :id accepts numeric ID or slug.

DELETE /api/monitors/:id

Delete a monitor and all its ping/alert history. :id accepts numeric ID or slug.

POST /api/monitors/:id/pause

Pause a monitor (stops alerting). Pings are still accepted but won't reset the deadline.

POST /api/monitors/:id/resume

Resume a paused monitor. Waits for the next ping to re-arm.

Alerts & Channels

GET /api/alerts

Recent alerts across all monitors (last 50).

GET /api/channels

List notification channels (email, webhook, telegram).

POST /api/channels

FieldTypeDescription
channel_type"email" | "slack" | "webhook" | "telegram"Alert delivery method
targetstringEmail address, webhook URL (HTTPS), or Telegram chat ID

DELETE /api/channels/:id

Remove a notification channel.

Account

GET /api/account

Returns: { email, api_key, plan, monitor_count, monitor_limit }

POST /api/account/rotate-key

Generate a new API key. The old key is immediately invalidated.

Rate Limits

EndpointLimit
Ping1 per second per slug
Auth (signup/login)10 per 15 minutes per IP
API60 per minute per user

Architecture

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:

  1. Ping ingestion — your cron job hits https://ping.trebben.dk/:slug. We record the timestamp and reset the monitor's deadline to now + grace_period.
  2. Checker loop — every 30 seconds, a background loop queries all active monitors where next_alert_at < now. Any monitor past its deadline is marked down.
  3. Alert dispatch — when a monitor transitions to 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.

Public Status API

Check any monitor's status by slug. No authentication required — the slug is the secret (same as pings).

GET /api/monitors/:slug/status

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.

Status Badges

Embed a live status badge in your README or dashboard. No authentication required — the slug is the secret (same as pings).

GET /badge/:slug.svg

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)
[![Backup Status](https://cronpulse.trebben.dk/badge/YOUR_SLUG.svg)](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.

GET /badge/cronpulse.svg

A generic "monitored by CronPulse" badge. No account needed — add it to any project README:

# Markdown
[![Monitored by CronPulse](https://cronpulse.trebben.dk/badge/cronpulse.svg)](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