# HelloCron documentation (full text) > Generated from https://docs.hellocron.com. Index with descriptions: https://docs.hellocron.com/llms.txt. API contract: https://docs.hellocron.com/openapi.yaml. --- # HelloCron Docs Section: Start. URL: https://docs.hellocron.com/ Summary: Job monitoring platform, documentation for developers. HelloCron is a monitoring platform for cron jobs, scheduled tasks, HTTP endpoints and SSL certificates. ## Quick links | | | |--|--| | [Introduction](/getting-started/introduction/) | What HelloCron is and how it works | | [Quick Start](/getting-started/quickstart/) | Send your first ping in 2 minutes | | [Authentication](/getting-started/authentication/) | API keys | | [POST /ping](/api/ping/) | Full API reference | | [Swagger UI](/reference/swagger/) | Interactive API explorer | | [AI agents and MCP](/guides/ai-agents/) | Let Claude, ChatGPT, Codex or Cursor set it up | ## Ecosystem ![How the HelloCron apps fit together: integrations send pings to the Ping API, agents talk to the MCP server, HelloCron itself probes your websites, events are processed into alerts, the dashboard and status pages](/ecosystem.svg) Every integration is open source on GitHub: | Repository | What it does | Get started | |--|--|--| | [hellocron/cli](https://github.com/hellocron/cli) | Shell client: wraps cron jobs and scripts with `run` / `complete` / `fail` pings | [Shell script guide](/guides/shell-script/) | | [hellocron/laravel](https://github.com/hellocron/laravel) | Laravel package: every Scheduler task reports its runs automatically | [Laravel guide](/guides/laravel/) | | [hellocron/php](https://github.com/hellocron/php) | PHP SDK: pings from any PHP app, monitors as code with a management key | `composer require hellocron/php` | | [hellocron/ping-action](https://github.com/hellocron/ping-action) | GitHub Action: reports scheduled workflow runs | `uses: hellocron/ping-action@v1` | | [hellocron/agent-plugin](https://github.com/hellocron/agent-plugin) | Skills and MCP connection for Claude, Codex, Cursor and ChatGPT | [AI agents guide](/guides/ai-agents/) | ## Features - **Ping API**: wrap any job with a `run` / `complete` / `fail` lifecycle - **HTTP monitoring**: uptime checks with configurable intervals - **SSL monitoring**: certificate expiry alerts - **Dashboard**: real-time event stream, failure analytics, slow job tracking - **Multi-user**: each user has their own API key and monitor namespace - **AI agents**: Agent Skills, a hosted MCP server and a plugin for Claude Code, Codex and ChatGPT --- # Authentication Section: Getting started. URL: https://docs.hellocron.com/getting-started/authentication/ Summary: How to authenticate API requests. All requests to the HelloCron API must be authenticated. Two methods are supported. ## Header (recommended) ```http Authorization: Bearer ``` This is the recommended method for production crons, recurring clients, and any traffic that touches shared infrastructure. The token never appears in URLs, access logs, browser history, or `Referer` headers. ## URL query parameter (convenience) For one-off curl commands, IoT devices, GitHub Actions, or anywhere setting a header is awkward, you can pass the key as `?api_key=`: ```bash curl "https://api.hellocron.com/ping/my-job?api_key=&status=complete" ``` Works on both `GET` and `POST` endpoints. If the `Authorization` header is present but malformed or invalid, the request is rejected. The query parameter is **not** consulted as a silent fallback. This prevents accidental bypass when a captured request is replayed with `?api_key=` appended. ### Security tradeoffs URL-embedded tokens are visible to: - HTTP access logs on every proxy, load balancer, and the server itself - The browser's history (if used from a browser) - The `Referer` header sent by the browser to any third-party resource on the resulting page - Any error report or analytics tool that captures URLs Use the URL method only for ad-hoc commands. Rotate the key if you suspect it has leaked into logs. ## Getting your key 1. Open [app.hellocron.com](http://app.hellocron.com) 2. Go to **Profile** → **API Key** 3. Copy the key, it is shown only once after generation ## Key scope Each API key is tied to a single user account. Events sent with a given key appear only in that user's dashboard. ## Errors | Status | Meaning | |--------|---------| | `401 Unauthorized` | Missing or invalid API key | | `403 Forbidden` | Key exists but lacks permission | ```json { "error": "unauthorized" } ``` --- # Introduction Section: Getting started. URL: https://docs.hellocron.com/getting-started/introduction/ Summary: What is HelloCron and how does it work? HelloCron is a **job monitoring platform** for cron jobs, scheduled tasks, HTTP endpoints and SSL certificates. ## What it monitors - **Cron jobs**: detect missed, failed, or long-running scheduled tasks - **HTTP endpoints**: uptime and response time checks - **SSL certificates**: expiry warnings before they become incidents ## How it works Every monitored job sends a ping to the HelloCron API at key lifecycle points: ``` job starts → POST /ping { status: "run" } job ends → POST /ping { status: "complete" } # or "fail" ``` HelloCron records each event, calculates durations, and surfaces failures in the dashboard. ## What HelloCron does | Capability | How it works | |------------|--------------| | Cron job monitoring | Your jobs send pings (run/complete/fail); missed or failed runs trigger alerts | | HTTP uptime checks | HelloCron requests your endpoints on a schedule and verifies status or content | | SSL certificate checks | Certificates are checked for upcoming expiry with configurable thresholds | | Dashboard & history | Every event is recorded with durations and output, browsable in the web panel | | API access | Manage monitors and send events programmatically — see the API Reference | --- # Quick Start Section: Getting started. URL: https://docs.hellocron.com/getting-started/quickstart/ Summary: Send your first ping in 2 minutes. ## 1. Get your API key Log in to the dashboard at [app.hellocron.com](http://app.hellocron.com) → Profile → API Key. ## 2. Send a ping ```bash curl -X POST http://api.hellocron.com/ping \ -H "Authorization: Bearer $HELLOCRON_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "event_type": "ping", "monitor": "my-first-job", "status": "complete", "duration": 12.4 }' ``` You should see `{"status":"success"}` and the event appear in the dashboard within seconds. ## 3. Wrap a real job ```bash #!/bin/bash API="http://api.hellocron.com/ping" export HELLOCRON_API_KEY="your-api-key-here" MON="my-backup" curl -sf $API -H "Authorization: Bearer $HELLOCRON_API_KEY" \ -d "{\"event_type\":\"ping\",\"monitor\":\"$MON\",\"status\":\"run\"}" # your actual job here /usr/local/bin/backup.sh EXIT=$? STATUS="complete" [ $EXIT -ne 0 ] && STATUS="fail" curl -sf $API -H "Authorization: Bearer $HELLOCRON_API_KEY" \ -d "{\"event_type\":\"ping\",\"monitor\":\"$MON\",\"status\":\"$STATUS\",\"exit_code\":$EXIT}" ``` Or use the bundled [shell script client](/guides/shell-script/). Prefer to delegate this? An AI assistant with the HelloCron plugin can install the client and wrap your jobs for you: see [AI agents and MCP](/guides/ai-agents/). --- # Event Types & States Section: API reference. URL: https://docs.hellocron.com/api/event-types/ Summary: All supported event_type values and their allowed states. ## event_type: ping The `status` field in the payload. Allowed values: | Status | Meaning | Color | |--------|---------|-------| | `run` | Job began execution | Blue | | `complete` | Job finished successfully (exit 0) | Green | | `fail` | Job failed (exit ≠ 0 or exception) | Red | | `skip` | Job intentionally skipped (maintenance window) | Gray | ## event_type: stream_event Any string is accepted for `state`. The UI maps keywords to colors: | State contains | Color | |---------------|-------| | `success`, `complete`, `ok` | Green | | `fail`, `error` | Red | | `start`, `running`, `pending` | Blue | | anything else | Gray | ## Task executions (HTTP / SSL checks) HTTP and SSL checks use a separate status set: | Status | Meaning | |--------|---------| | `pending` | Queued, not yet started | | `running` | Worker is executing the check | | `success` | Check passed | | `failed` | Check failed | | `retrying` | Transient failure, retrying (up to 3×) | --- # Management API Section: API reference. URL: https://docs.hellocron.com/api/monitors/ Summary: Manage monitors programmatically with the HelloCron REST API. Create, read and update monitors from scripts, CI pipelines and infrastructure-as-code tooling. The API speaks the same manifest format you can export and import in the panel, so a manifest downloaded from the panel works as an API payload and vice versa. ## Base URL and authentication ```http https://app.hellocron.com/api/v1 Authorization: Bearer ``` The Management API uses its **own key** (prefix `mk_`), separate from the Ingest API key used for pings. Generate it in the panel under **Settings → API key** (Management API Key section). All requests and responses are `application/json`. Error messages are always in English. ## Rate limit 60 requests per minute per API key. Exceeding the limit returns `429 Too Many Requests`. Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining` headers. ## The manifest format Every monitor is described by a manifest with `manifest_version: 1` and one of three kinds: | Kind | What it monitors | |------|------------------| | `ping` | A cron job or scheduled task that sends pings | | `http_check` | An HTTP endpoint checked on a schedule | | `ssl_check` | An SSL certificate checked for expiry | ### Ping monitor ```json { "manifest_version": 1, "kind": "ping", "name": "db-backup", "enabled": true, "timeout_seconds": 60, "expected_interval_seconds": 86400, "grace_seconds": 300, "tags": ["prod", "backup"] } ``` The `name` is the slug you ping (`a-zA-Z0-9_-`, max 64 chars) and it is immutable after creation. `expected_interval_seconds` and `grace_seconds` are optional. `display_name` (optional, max 255 chars) is the human label shown in the panel instead of the slug; omit it to clear it. `project` (optional, max 100 chars) puts the monitor into the project of that name, creating it when needed, exactly like `--project` on a ping; omitting the key leaves the current project untouched. All three kinds also accept an optional `notification_group` key: the NAME of a notification group on the account. When set, alerts for the monitor go only to that group's channels. Omitting the key detaches the group (manifests replace state wholesale); an unknown name fails with error code `notification_group_invalid`. See the [alert channels guide](/guides/alert-channels/#notification-groups). ### HTTP check ```json { "manifest_version": 1, "kind": "http_check", "name": "Website health", "enabled": true, "schedule": "*/5 * * * *", "tags": ["prod"], "config": { "url": "https://example.com/health", "method": "GET", "timeout": 30, "expected_status": 200, "expected_content": "" } } ``` `schedule` accepts either a standard 5-field cron expression (`*/5 * * * *`) or an interval shorthand (`30s`, `5m`, `1h`, `1d`, `7d`). At least one of `expected_status` or `expected_content` must be set. ### SSL check ```json { "manifest_version": 1, "kind": "ssl_check", "name": "example.com certificate", "enabled": true, "schedule": "0 6 * * *", "config": { "domain": "example.com", "warning_days": 30, "alert_days": 7 } } ``` ## Endpoints API responses add a read-only `uuid` field to the manifest. A `uuid` sent in a request body is ignored. ### List monitors ```bash curl -H "Authorization: Bearer $API_KEY" \ https://app.hellocron.com/api/v1/monitors ``` Optional filter: `?kind=ping`, `?kind=http_check` or `?kind=ssl_check`. ```json { "monitors": [ { "uuid": "3b0043f4-...", "manifest_version": 1, "kind": "ping", "name": "db-backup", ... } ] } ``` ### Get a monitor ```bash curl -H "Authorization: Bearer $API_KEY" \ https://app.hellocron.com/api/v1/monitors/ ``` Returns the manifest with `uuid`. Unknown uuid returns `404`. ### Create a monitor ```bash curl -X POST \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"manifest_version":1,"kind":"ping","name":"db-backup","timeout_seconds":60}' \ https://app.hellocron.com/api/v1/monitors ``` Returns `201 Created` with the stored manifest including its `uuid`. Duplicate names and plan limits are rejected with `422`. ### Update a monitor ```bash curl -X PUT \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"manifest_version":1,"kind":"ping","name":"db-backup","timeout_seconds":120}' \ https://app.hellocron.com/api/v1/monitors/ ``` Send the full manifest, not a partial patch. The `kind` must match the existing monitor and a ping monitor's `name` cannot change; both violations return `422`. ### Delete a monitor Deletion is irreversible: removing a ping monitor also removes its event history, expected executions and related notifications. A bare `DELETE` is therefore refused with `403` and a link to the panel, so a mistyped script or a generic CRUD client cannot wipe data by accident: ```json { "message": "Deleting a monitor is irreversible. Repeat the request with ?confirm=true, or delete it from the web panel.", "panel_url": "https://app.hellocron.com/monitors//edit" } ``` Add `?confirm=true` to actually delete. The response is `204 No Content` with an empty body: ```bash curl -sS -X DELETE \ -H "Authorization: Bearer $HELLOCRON_MANAGEMENT_KEY" \ "https://app.hellocron.com/api/v1/monitors/?confirm=true" ``` Works for all three kinds. For `http_check` and `ssl_check` only the check and its execution history go away; for `ping` monitors the monitor name is released, so a monitor re-created later with the same name starts with a clean history. ## Config as code Instead of driving the endpoints above one monitor at a time, you can keep your whole monitoring setup in a single file, commit it to your repository, and reconcile the account with it in one request. A **bundle** is the manifest format wrapped in an array: ```json { "manifest_version": 1, "monitors": [ { "manifest_version": 1, "kind": "ping", "name": "db-backup", "timeout_seconds": 60 }, { "manifest_version": 1, "kind": "http_check", "name": "Website health", "schedule": "5m", "config": { "url": "https://example.com/health", "expected_status": 200 } } ] } ``` Monitors are matched by `kind` and `name`, not by `uuid`, so a bundle is portable between accounts and readable in a pull request. Ping monitors and checks have separate name spaces: a `ping` named `api` and an `http_check` named `api` are two different monitors and neither collides with the other. ### Export the account as a bundle ```bash curl -H "Authorization: Bearer $HELLOCRON_MANAGEMENT_KEY" \ https://app.hellocron.com/api/v1/monitors/export > monitors.json ``` The output is a ready-to-apply bundle with no `uuid` fields. This is the fastest way to adopt config as code on an account that was set up through the panel: export once, commit the file, and manage it from there. ### Apply a bundle ```bash curl -X POST \ -H "Authorization: Bearer $HELLOCRON_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ --data-binary @monitors.json \ "https://app.hellocron.com/api/v1/monitors/apply?dry_run=true" ``` `dry_run=true` reports what would change and writes nothing. Drop it to actually apply. Both modes return `200` and the same report: ```json { "dry_run": true, "summary": { "create": 1, "update": 1, "unchanged": 5, "orphaned": 2 }, "changes": [ { "name": "db-backup", "kind": "ping", "action": "update", "uuid": "3b0043f4-...", "diff": { "grace_seconds": [300, 600] } }, { "name": "etl-job", "kind": "ping", "action": "create" } ], "orphaned": [ { "name": "old-cleanup-job", "kind": "ping", "uuid": "9c1f77a2-..." } ] } ``` Three properties worth relying on: - **Apply never deletes.** Monitors that exist on the account but are missing from the bundle are listed under `orphaned` and left untouched. Removing a monitor stays a deliberate act: `DELETE ?confirm=true`, or the panel. - **All or nothing.** The whole bundle is validated first. If any entry is invalid the request returns `422` and nothing is written, so a typo in the tenth monitor cannot leave the first nine half-applied. - **Idempotent.** Applying an unchanged bundle reports everything as `unchanged` and performs no writes, which makes it safe to run on every push. Errors are reported per position in the bundle: ```json { "message": "The given data was invalid.", "errors": { "monitors.3": ["The \"schedule\" field must be a cron expression (5 fields) or an interval such as 5m, 1h, 1d."] } } ``` ### Example: reconcile monitors from CI Dry-run on pull requests so reviewers see the diff, apply on merge: ```yaml - name: Check monitor changes if: github.event_name == 'pull_request' run: | curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer ${{ secrets.HELLOCRON_MANAGEMENT_KEY }}" \ -H "Content-Type: application/json" \ --data-binary @monitors.json \ "https://app.hellocron.com/api/v1/monitors/apply?dry_run=true" - name: Apply monitors if: github.ref == 'refs/heads/main' run: | curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer ${{ secrets.HELLOCRON_MANAGEMENT_KEY }}" \ -H "Content-Type: application/json" \ --data-binary @monitors.json \ https://app.hellocron.com/api/v1/monitors/apply ``` ### Using the shell client instead of curl From v1.3 the client wraps both endpoints: ```bash hellocron export -o monitors.json # download the account as a bundle hellocron apply -f monitors.json --dry-run hellocron apply -f monitors.json ``` The client reads the **management** key from `HELLOCRON_MANAGEMENT_KEY`, falling back to `~/.hellocron-management.conf` (written by `hellocron configure --management-key`, permissions 600). That file is deliberately separate from `~/.hellocron.conf`: the ingest key belongs on every monitored server and is often distributed by configuration management, while the management key can delete monitors together with their event history. Keeping them apart means shipping your ingest config around never fans out a destructive credential. Passing the wrong kind of key is caught before the request goes out, so you get an explanation rather than a bare `401`. Exit status is `0` for a successful apply and `1` for any error, which is what CI needs. Config as code is available on every plan by default. If it has been disabled for your plan, `apply` returns `403` with a link to pricing; `export` keeps working regardless. ## Error responses | Status | Meaning | |--------|---------| | `401` | Missing or invalid API key | | `404` | Monitor not found (or belongs to another account) | | `422` | Invalid manifest, duplicate name, immutable field or plan limit reached | | `403` | DELETE without `?confirm=true`, or `apply` on a plan without config as code | | `429` | Rate limit exceeded | Validation errors use this shape: ```json { "message": "A Ping monitor name is immutable. To use a different name, import the manifest as a new monitor.", "errors": { "manifest": ["A Ping monitor name is immutable. To use a different name, import the manifest as a new monitor."] }, "error_codes": { "manifest": ["name_immutable"] } } ``` ### Machine-readable error codes `errors` is meant for humans and its wording changes over time. Anything programmatic should read `error_codes`, which mirrors `errors` key for key and position for position with stable identifiers. Errors with a single cause (the `403`s above, for example) carry a flat `code` field instead. For bundles the keys carry the position, matching Laravel's array validation format: ```json { "message": "The given data was invalid.", "errors": { "monitors.3": ["The \"schedule\" field must be a cron expression (5 fields) or an interval such as 5m, 1h, 1d."] }, "error_codes": { "monitors.3": ["schedule_invalid"] } } ``` Current codes: `manifest_version_unsupported`, `invalid_json`, `kind_invalid`, `name_invalid`, `name_charset_invalid`, `timeout_out_of_range`, `interval_out_of_range`, `grace_out_of_range`, `schedule_invalid`, `domain_invalid`, `url_invalid`, `method_invalid`, `check_timeout_invalid`, `http_assertion_required`, `kind_mismatch`, `name_immutable`, `name_already_exists`, `name_taken_by_other_kind`, `plan_limit_reached`, `bundle_invalid`, `monitors_missing`, `entry_not_object`, `duplicate_entry`, `delete_requires_confirm`, `config_as_code_disabled`. New codes get added over time and existing ones are never renamed or repurposed, so treat an unrecognised value as a generic failure rather than rejecting the response. ### Machine-readable API description The full OpenAPI 3 description lives at [docs.hellocron.com/openapi.yaml](https://docs.hellocron.com/openapi.yaml) and covers both the Ingest and Management APIs. Point a generator at it to get a typed client in your language of choice. A [Postman collection](https://docs.hellocron.com/hellocron-postman.json) is available too. ## Example: create a monitor from CI A GitHub Actions step that registers a monitor after every deploy (idempotent: a `422` duplicate response means the monitor already exists): ```yaml - name: Ensure deploy monitor exists run: | STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ -H "Authorization: Bearer ${{ secrets.HELLOCRON_API_KEY }}" \ -H "Content-Type: application/json" \ -d '{"manifest_version":1,"kind":"ping","name":"nightly-report","expected_interval_seconds":86400}' \ https://app.hellocron.com/api/v1/monitors) if [ "$STATUS" != "201" ] && [ "$STATUS" != "422" ]; then echo "Unexpected status $STATUS"; exit 1 fi ``` --- # API Overview Section: API reference. URL: https://docs.hellocron.com/api/overview/ Summary: HelloCron APIs, base URLs, authentication and rate limits. HelloCron exposes **two APIs**, each with its own API key: | API | Base URL | Key prefix | Purpose | |-----|----------|------------|---------| | **Ingest API** | `https://api.hellocron.com` | `ck_` | Receive monitoring events (pings) from your jobs and services | | **Management API** | `https://app.hellocron.com/api/v1` | `mk_` | Manage monitors as manifest documents: list, get, create, update | ## Authentication Both APIs authenticate with a Bearer token, but each uses its **own key**: ```http Authorization: Bearer ``` - The **Ingest API key** (`ck_...`) authenticates pings only. - The **Management API key** (`mk_...`) authenticates `/api/v1` only. Generate both keys in the panel under **Settings → API key**. The Ingest API additionally accepts an `?api_key=` query parameter for ad-hoc GET pings (see [GET /ping](/api/ping-get/)). ### Scoped management keys Besides the personal `mk_` key (full access), you can create additional named keys under **Settings → API key → Management API**, each with an explicit set of scopes: | Scope | Grants | Typical use | |-------|--------|-------------| | `read` | `GET` requests: list, get, export | dashboards, backups of your config | | `write` | `POST` / `PUT`: create, update, [apply](/api/monitors/#bundle-export-and-apply) | CI deploys, integrations | | `delete` | `DELETE` (still requires `?confirm=true`) | almost never; deleting a monitor erases its event history | A request outside the key's scopes returns `403` with `error_code: "insufficient_scope"` and a message naming the missing scope. Keys are revocable independently, so a leaked CI key does not force rotating anything else. Recommended setup for automation: a `read` + `write` key. Since `apply` never deletes monitors, that key covers a full config-as-code workflow with no ability to destroy data. ## Content type All request bodies must be `application/json`. All responses are `application/json`. ## Rate limits Each API has its own limit: | API | Limit | On exceeding | |-----|-------|--------------| | Ingest API | 10 requests/second, burst 20 | `429 Too Many Requests` | | Management API | 60 requests/minute per API key | `429` + `X-RateLimit-Limit` / `X-RateLimit-Remaining` headers | ## Endpoints ### Ingest API | Method | Path | Description | |--------|------|-------------| | `POST` | `/ping` | Submit a monitoring event — see [POST /ping](/api/ping/) | | `GET` | `/ping/{monitor}` | Submit an event via query params — see [GET /ping](/api/ping-get/) | | `GET` | `/health` | API health check (no auth required) | Status vocabulary and event types: [Event Types & States](/api/event-types/). ### Management API | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v1/account` | Account plan and monitor usage | | `GET` | `/api/v1/monitors` | List monitor manifests (filter with `?kind=`) | | `GET` | `/api/v1/monitors/{uuid}` | Get a single monitor | | `GET` | `/api/v1/monitors/export` | Export the whole account as a bundle | | `POST` | `/api/v1/monitors` | Create a monitor from a manifest | | `POST` | `/api/v1/monitors/apply` | Apply a bundle (config-as-code, never deletes) | | `PUT` | `/api/v1/monitors/{uuid}` | Update a monitor (full manifest) | | `DELETE` | `/api/v1/monitors/{uuid}` | Delete with explicit `?confirm=true`; a bare `DELETE` returns `403` | Full reference with the manifest format: [Management API](/api/monitors/). ## Interactive tools - [Swagger UI](/reference/swagger/) — try both APIs in the browser - [Postman Collection](/reference/postman/) — ready-made requests for all endpoints --- # POST /ping Section: API reference. URL: https://docs.hellocron.com/api/ping/ Summary: Send heartbeat pings to track cron jobs and scheduled tasks. A simple, Cronitor-API-compatible ping endpoint - a lightweight alternative to PostPing, Cronitor, and Healthchecks.io. ## Request ```http POST /ping Authorization: Bearer Content-Type: application/json ``` ### Body fields | Field | Type | Required | Description | |-------|------|----------|-------------| | `event_type` | string | yes | `ping`, `stream_event`, or custom | | `monitor` | string | yes | Monitor name (letters, digits, `-` and `_`, 1-64 chars) | | `status` | string | yes* | Event status, see [Event Types & States](/api/event-types/) | | `duration` | float | no | Execution time in seconds | | `exit_code` | int | no | Process exit code | | `host` | string | no | Hostname that ran the job | | `project` | string | no | Project name (max 100 chars); the monitor is grouped under it in the panel, the project is created if needed | | `message` | string | no | Free-form message / log excerpt | | `timestamp` | int | no | Unix timestamp (defaults to now) | *For `event_type: "ping"` the field name is `status`. Allowed values: `run`, `complete`, `fail`, `skip`. ### Example: job lifecycle ```json // Job started { "event_type": "ping", "monitor": "db-backup", "status": "run", "host": "server-01" } // Job finished successfully { "event_type": "ping", "monitor": "db-backup", "status": "complete", "duration": 47.3, "exit_code": 0 } ``` ### Example: skip (maintenance window) ```json { "event_type": "ping", "monitor": "payment-service", "status": "skip" } ``` For quick shell one-liners without a JSON body, use [GET /ping](/api/ping-get/). It accepts the same status values and supports `?api_key=` URL authentication. ## Response ### 200 OK ```json { "status": "success" } ``` ### 400 Bad Request ```json { "error": "required field missing: status" } ``` ### 401 Unauthorized ```json { "error": "unauthorized" } ``` ### 403 Forbidden Returned when the ping would create a **new** monitor and the account is already at its plan's monitor limit. Events for monitors that already exist are always accepted, so hitting the limit - or downgrading a plan - never stops the monitoring you already have. ```json { "status": "error", "code": "monitor_limit_reached", "message": "Monitor limit reached (30). Delete unused monitors or upgrade your plan." } ``` ### 429 Too Many Requests Rate limit. **The monthly event quota never answers 4xx** - see the quota headers below. ## Quota headers Every ping answers with the account's standing, so a client can warn long before anything stops working: | Header | Meaning | |---|---| | `X-Quota-State` | `ok`, `warning` (from 80% of the limit), `exceeded`, or `suspended` | | `X-Quota-Limit` | Monthly event allowance of the plan. Absent on plans without a limit | | `X-Quota-Used` | Events accepted so far in the current period | | `X-Quota-Reset` | When the counter starts over, RFC 3339 in UTC | | `X-Quota-Reset-In` | Seconds until that moment | Running out of quota does **not** make a ping fail. The request still answers `200`, because a ping usually comes from a `curl` line inside a crontab: a 4xx would make cron report a job that ran perfectly as failed, and mail its owner about it. A billing problem must not become a production incident. Going over the limit starts a grace period, during which events are still accepted and the overage is visible in the panel. Only after it runs out is the account's monitoring suspended; from then on pings answer: ```json { "status": "ok", "quota": "suspended", "resets_at": "2026-10-01T00:00:00Z", "message": "Monitoring is suspended because the account is over its plan limit. The event was not stored." } ``` The event is not stored, and alerting stays silent for the whole account - a suspended monitor must not raise a failure that is not happening. Monitoring resumes on its own when the quota resets, when the account drops back under its monitor limit, or as soon as the plan is upgraded. --- # GET /ping Section: API reference. URL: https://docs.hellocron.com/api/ping-get/ Summary: Submit a monitoring event via a simple GET request with query parameters. A `GET` request to `/ping/` is the simplest way to record a monitoring event. It is designed for shell one-liners, cron jobs, IoT devices, healthchecks from routers/NAS appliances, and any environment where setting request headers or building a JSON body is awkward. ## Request ```http GET /ping/?status=[&...] ``` The `` is taken from the URL path. All event fields are query parameters. ### Authentication You can authenticate in two ways. See [Authentication](/getting-started/authentication/) for the security tradeoffs. ```bash # Header (recommended for recurring traffic) curl -H "Authorization: Bearer " \ "https://api.hellocron.com/ping/db-backup?status=complete" # URL query parameter (convenience, token visible in logs/history/Referer) curl "https://api.hellocron.com/ping/db-backup?api_key=&status=complete" ``` The `Authorization` header takes priority. If it is present but malformed or invalid, the request is rejected even when `?api_key=` is also provided, with no silent fallback. ### Query parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `api_key` | string | conditional | API key when not using the `Authorization` header | | `status` | string | yes | Event status: `run`, `complete`, `fail`, `skip` | | `duration` | float | no | Execution time in seconds | | `exit_code` | int | no | Process exit code | | `host` | string | no | Hostname that ran the job | | `msg` | string | no | Free-form message / log excerpt (URL-encoded). With `status=fail` it is stored as error diagnostics; with any other status it is attached as a plain message | | `series` | string | no | Correlation ID grouping `run`/`complete`/`fail` of the same execution | | `run_source` | string | no | Where the run came from, e.g. `cron`, `shell`, `github_actions` | ## Examples ### Job lifecycle (correlated via `series`) ```bash SERIES=$(uuidgen) curl "https://api.hellocron.com/ping/db-backup?status=run&series=$SERIES" # ... job runs ... curl "https://api.hellocron.com/ping/db-backup?status=complete&series=$SERIES&duration=47.3&exit_code=0" ``` ### Failure with message ```bash curl "https://api.hellocron.com/ping/db-backup?status=fail&msg=DB+timeout&exit_code=1" ``` ### Skip (maintenance window) ```bash curl "https://api.hellocron.com/ping/payment-service?status=skip" ``` ### Crontab one-liner (header auth) ```cron 0 3 * * * /usr/local/bin/pg_dump db > /backups/db.sql && \ curl -s -H "Authorization: Bearer $API_KEY" \ "https://api.hellocron.com/ping/db-backup?status=complete" >/dev/null ``` ## Response ### 200 OK ```json { "status": "success", "message": "Ping accepted", "monitor": "db-backup", "timestamp": 1779650795 } ``` ### 400 Bad Request ```json { "error": "required field missing: status" } ``` ### 401 Unauthorized ```json { "error": "unauthorized" } ``` For richer payloads (tags, projects, structured details), use [POST /ping](/api/ping/) with a JSON body. --- # AI agents and MCP Section: Guides. URL: https://docs.hellocron.com/guides/ai-agents/ Summary: Let Claude, ChatGPT, Codex, Cursor or Gemini set up HelloCron monitoring for you, from skills to the remote MCP server. HelloCron ships one package for AI assistants and coding agents: three [Agent Skills](https://agentskills.io/) that teach the model how to use the shell client, design monitoring and call the API, plus a remote [MCP](https://modelcontextprotocol.io/) server that lets the model manage monitors on your account. Everything lives in the public [hellocron/agent-plugin](https://github.com/hellocron/agent-plugin) repository. ## What you get | Component | What it does | Works in | |---|---|---| | Skills (`SKILL.md`) | Instructions the agent loads on demand: install and use `hellocron.sh`, pick intervals and grace, wrap cron jobs, write bundles, call the API | Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI and every tool that reads the Agent Skills format | | MCP server | Tools such as `list_monitors`, `create_monitor`, `apply_monitor_bundle`, `ping`, backed by your API keys | Claude (Desktop, Code, claude.ai), ChatGPT (Developer Mode), Codex, Cursor, Gemini CLI, VS Code | | Plugin package | Skills and the MCP connection bundled in the [Agent Plugins](https://agent-plugins.org/) format so one install adds both | Claude Code, Codex, ChatGPT | | `llms.txt` | Index of these docs for models: [`/llms.txt`](/llms.txt) and the full text at [`/llms-full.txt`](/llms-full.txt) | any agent with web access | The MCP server never stores your keys. Each request is forwarded to the public API with the `Authorization` header you configured in the client, so plan limits, rate limits and key scopes apply exactly as they do for curl. ## Keys Create keys in the panel under Settings → API keys: - an **ingest key** (`ck_...`) for pings; safe to put on monitored servers, - a **management key** (`mk_...`) for listing, creating, updating, deleting and applying monitors; keep it on your workstation or in CI secrets only. Give the MCP client the management key when you want the agent to manage monitors, the ingest key when it should only send pings. ## Claude Code ```bash claude plugin marketplace add hellocron/agent-plugin claude plugin install hellocron@hellocron ``` The plugin registers the skills (`/hellocron:hellocron-cli`, `/hellocron:hellocron-monitoring`, `/hellocron:hellocron-api`) and the MCP server. Set the key once: ```bash claude mcp add --transport http hellocron https://mcp.hellocron.com/mcp \ --header "Authorization: Bearer mk_..." ``` ## Codex CLI and ChatGPT ```bash codex plugin marketplace add hellocron/agent-plugin ``` Then enable the HelloCron plugin in Codex or ChatGPT. When asked for the connection, paste `https://mcp.hellocron.com/mcp` and your key. Without the plugin, ChatGPT Developer Mode accepts the same URL as a custom MCP connection, and a Custom GPT can use the API directly through Actions: import `https://docs.hellocron.com/openapi.yaml` and choose API key authentication with the `Authorization: Bearer` header. ## Cursor, Gemini CLI, VS Code, other MCP clients Add the server to the client's MCP configuration: ```json { "mcpServers": { "hellocron": { "type": "streamable-http", "url": "https://mcp.hellocron.com/mcp", "headers": { "Authorization": "Bearer mk_..." } } } } ``` For the skills, copy the `skills/` directory of the repository into the location your tool reads (`.cursor/skills/`, `.gemini/skills/`, `.agents/skills/` or the project's `skills/`; see the tool's documentation). The files are plain Markdown and need no build step. ## Example prompts - "Install the HelloCron client on this server, verify it with doctor and wrap every job in `/etc/cron.d` so failures alert me." - "Create an HTTP check for `https://api.example.com/health` every minute expecting a 200 and the text `ok`, and an SSL check for `example.com`." - "Export my monitors as a bundle, add a nightly `db-backup` ping monitor with one hour of grace and apply it as a dry run first." ## Tools exposed by the MCP server | Tool | Endpoint | Notes | |---|---|---| | `get_account` | `GET /api/v1/account` | read-only | | `list_monitors`, `get_monitor` | `GET /api/v1/monitors[/{uuid}]` | read-only | | `export_monitors` | `GET /api/v1/monitors/export` | read-only | | `create_monitor`, `update_monitor` | `POST`, `PUT /api/v1/monitors` | manifests, see [Monitors](/api/monitors/) | | `apply_monitor_bundle` | `POST /api/v1/monitors/apply` | `dry_run` supported, never deletes | | `delete_monitor` | `DELETE /api/v1/monitors/{uuid}?confirm=true` | destructive, requires `confirm: true` | | `ping` | `POST /ping` | needs an ingest key | | `get_health` | `GET /health` | reachability | Tools carry MCP annotations (`readOnlyHint`, `destructiveHint`) so clients can ask for confirmation before writes. The full contract is the [OpenAPI document](/openapi.yaml). --- # Alert Channels Section: Guides. URL: https://docs.hellocron.com/guides/alert-channels/ Summary: Deliver monitor alerts to email, Telegram, Discord, Slack, PagerDuty, or any webhook endpoint. HelloCron can notify you about monitor events (failures, missed runs, timeouts, recoveries) through several channels. You can configure any number of channels and choose which event types each channel receives. All channels are managed in the panel under **Settings -> Notification Channels**. Every channel has a **Test** button that sends a test notification only to that channel, so you can verify the configuration before relying on it. | Channel | Availability | |---|---| | Email | all plans | | Telegram | all plans | | Discord | all plans | | Webhook | plan with webhook alerting | | Slack | plan with Slack alerting | | PagerDuty | plan with PagerDuty alerting | ## Email The simplest channel. Leave the address field empty to use your account email, or enter a different address (for example a team alias). ## Telegram Telegram alerts are free and instant, and connecting takes one click. 1. In the panel, add a channel of type **Telegram** and click **Connect Telegram**. 2. Scan the QR code with your phone (or click **Open in Telegram**) and press **Start** in the chat that opens. For a group, use **Add to a group** instead and pick the group. 3. The form fills in by itself and shows "Connected". Save the channel and click **Test**. Alerts are delivered by the official HelloCron bot. No tokens, no chat IDs, nothing to look up. **Advanced: your own bot.** If you prefer alerts to come from a bot you control, expand *Advanced: use your own bot* in the form: create a bot via [@BotFather](https://t.me/BotFather) (`/newbot`, copy the token in the `123456789:AAF...` format), get the chat ID from `https://api.telegram.org/bot/getUpdates` (group IDs are negative), and enter both fields. A channel with its own token always sends through that bot. HelloCron stores the token for delivery only and never includes it in logs. ## Discord Discord alerts use channel webhooks, no bot required. 1. In Discord, open the target channel settings: **Integrations -> Webhooks -> New Webhook**. 2. Copy the webhook URL (it starts with `https://discord.com/api/webhooks/`). 3. In the panel, add a channel of type **Discord** and paste the URL. 4. Click **Test**. Alerts arrive as embeds, green for recoveries and red for failures. ## Slack 1. Create an [incoming webhook](https://api.slack.com/messaging/webhooks) in your Slack workspace. 2. In the panel, add a channel of type **Slack** and paste the webhook URL (starts with `https://hooks.slack.com/services/`). 3. Click **Test**. ## PagerDuty PagerDuty alerts use the Events API v2, so failures open incidents and recoveries resolve them automatically. 1. In PagerDuty, create a service (or open an existing one) and add an **Events API v2** integration: **Service -> Integrations -> Add integration -> Events API v2**. 2. Copy the **Integration Key** (also called a routing key, 32 characters). 3. In the panel, add a channel of type **PagerDuty** and paste the key. 4. Click **Test**. How events map: - **Failed**, **Missed** and **Timeout** trigger an incident with `critical` severity; **Degraded** and **Still failing** use `warning`. - **Recovered** resolves the incident opened for that monitor, using a shared deduplication key, so one flapping monitor never piles up incidents. - Every incident carries a link back to the monitor in the HelloCron panel. ## Webhook Sends a JSON payload to any HTTP endpoint, useful for integrating with your own systems, on-call tools, or automation. ```json { "id": 123, "type": "failed", "monitor_name": "db-backup", "message": "Monitor db-backup failed", "metadata": {}, "occurred_at": "2026-07-24T18:00:00+00:00" } ``` - Method: `POST` (default) or `GET` (payload as query parameters). - Custom headers: one per line as `Header-Name: value`, for example an `Authorization` header for your endpoint. - Slack and Discord webhook URLs are rejected here on purpose: their APIs expect a different payload format. Use the dedicated Slack or Discord channel type instead. ### Variables The payload above is the default. When the receiving system expects its own format, put variables in the URL, the body, or both: | Variable | Value | |---|---| | `$MONITOR` | Monitor name | | `$STATUS` | Event type: `failed`, `recovered`, `missed`, `timeout`, `degraded`, `still_failing` | | `$MESSAGE` | Alert message | | `$ID` | Notification id | | `$TIME` | Time of the event, ISO 8601 | A custom body is sent exactly as written, so the receiving system decides the format, not us: ```json {"text": "$MONITOR is $STATUS", "detail": "$MESSAGE"} ``` Variables also work in the URL, which is the only option for systems that accept alerts through query parameters and no request body: ``` https://example.com/hook?monitor=$MONITOR&status=$STATUS ``` Escaping is handled per context and you do not need to think about it: values in the URL are percent-encoded, values in the body are escaped as JSON string content. A monitor named `nightly backup & sync` will not break the query string, and an error message containing quotes will not break the JSON. Leave the body empty to keep the default payload. ## Notification groups A notification group is a named set of channels. A monitor assigned to a group alerts only that group's channels; monitors without a group keep the default behaviour and alert every enabled channel on the account. Typical setup: a "backups" group pointing at a dedicated Telegram chat and a "www" group pointing at the on-call webhook. Because an account can have several channels of the same type, each group can target its own Telegram chat. Manage groups in **Settings -> Notification channels -> Manage groups**: create a group, tick its channels, and attach monitors (ping and HTTP/SSL checks alike) on the same page. You can also pick a group when editing a single monitor. Two details worth knowing: - A group with no channels silences its monitors outside the panel (the in-app bell still works). The panel warns about this. - Deleting a group never deletes anything else: its monitors fall back to all account channels. In [config-as-code](/api/monitors/) manifests the group travels as `notification_group` (the group's name). Omitting the key detaches the group; unknown names are rejected with the error code `notification_group_invalid`. ## Event types Each channel subscribes to a subset of event types: | Event | Meaning | |---|---| | Failed | the job reported a failure | | Missed | an expected run did not arrive in time | | Timeout | the job started but did not complete in time | | Degraded | the check is failing intermittently | | Recovered | the monitor is healthy again | | Still failing | periodic reminder while a failure is ongoing | --- # Monitoring Cron Jobs Section: Guides. URL: https://docs.hellocron.com/guides/cron-jobs/ Summary: Wrap any cron job to track start, success, and failure. ## Basic pattern Add two pings around your command, one at start, one at end: ```bash # /etc/cron.d/my-app # Note the ";" after the first ping: if the API is unreachable, your job still runs. */5 * * * * root hellocron ping my-job run; /opt/my-app/run.sh && hellocron ping my-job complete || hellocron ping my-job fail ``` ## With exit code tracking ```bash #!/bin/bash # wrapper.sh hellocron ping db-backup run pg_dump mydb | gzip > /backups/db-$(date +%Y%m%d).sql.gz EXIT=$? if [ $EXIT -eq 0 ]; then hellocron ping db-backup complete --duration $SECONDS else hellocron ping db-backup fail --exit-code $EXIT fi ``` ## Crontab entry ```cron 0 3 * * * root /usr/local/bin/wrapper.sh ``` ## Duration tracking Pass `--duration` in seconds for chart data in the dashboard: ```bash START=$(date +%s) /usr/local/bin/my-job.sh DURATION=$(( $(date +%s) - START )) hellocron ping my-job complete --duration $DURATION ``` ## Silent jobs (no output) Redirect all output to prevent cron from sending emails: ```cron 0 * * * * root /usr/local/bin/wrapper.sh > /dev/null 2>&1 ``` --- # Laravel Scheduler Section: Guides. URL: https://docs.hellocron.com/guides/laravel/ Summary: Monitor every Laravel Scheduler task with the hellocron/laravel package - automatic run/complete/fail pings, durations, exit codes and monitor sync. The `hellocron/laravel` package instruments the Laravel Scheduler automatically. Install it, set one key, and every scheduled task reports `run` when it starts and `complete` or `fail` when it ends, with duration and exit code. When a task stops running altogether, the missing report raises the alert, which is the failure mode `schedule:run` logs can never show you. ## Installation ```bash composer require hellocron/laravel ``` Add your ingest key (panel, starts with `ck_`) to `.env`: ``` HELLOCRON_INGEST_KEY=ck_your_key ``` Done. The next `schedule:run` starts pinging, and monitors are created automatically on first ping, subject to your plan's monitor limit. ## What gets reported - `run` on start, `complete` on success, `fail` on a non-zero exit code or an exception (with the message), `skip` when a filter such as `withoutOverlapping` prevents the run - duration in seconds, exit code, hostname - a `series` id correlating each run's start and end, so overlapping runs of the same task never pair up wrong (see [Ping via GET](/api/ping-get/)) Monitor names derive from the command: `laravel--inspire`. The hash comes from `app.url`, so several apps on one account stay apart. Override the prefix with `HELLOCRON_PREFIX`. ## Monitor sync (optional) Pings alone create monitors with default settings. To set expected intervals and grace periods computed from each task's actual cron expression, add a [Management API](/api/monitors/) key (`mk_`, scopes read + write) and run: ```bash php artisan hellocron:sync --dry-run php artisan hellocron:sync ``` The command creates missing monitors, updates existing ones and reports monitors that no longer match any scheduled task. It never deletes anything. Run it after deployments that change the schedule. ## Configuration ```bash php artisan vendor:publish --tag=hellocron-config ``` | Key | Env | Default | |---|---|---| | `enabled` | `HELLOCRON_ENABLED` | `true` | | `ingest_key` | `HELLOCRON_INGEST_KEY` | none (package inert without it) | | `management_key` | `HELLOCRON_MANAGEMENT_KEY` | none (only `hellocron:sync` needs it) | | `prefix` | `HELLOCRON_PREFIX` | `laravel--` | | `tags` | - | `[]` (sync always adds `laravel` and the hostname) | ## Safety Monitoring must never take your app down. Pings use a 1 second connect and 2 second request timeout, and every failure is swallowed: if the monitoring endpoint is unreachable, your tasks run exactly as before. The Management API is only called from the `hellocron:sync` console command, never while the schedule executes. ## Requirements PHP 8.1+, Laravel 10, 11 or 12. --- # Migrating to HelloCron Section: Guides. URL: https://docs.hellocron.com/guides/migration/ Summary: Switch from Cronitor, PostPing, Healthchecks.io, or any other cron/ping monitoring tool. ## From Cronitor HelloCron's [ping API](/api/ping/) is deliberately compatible with Cronitor's ping format - same `status` values (`run`, `complete`, `fail`, `skip`), same optional fields (`duration`, `exit_code`, `host`, `msg`), and the same `?api_key=` / `?series=` query params on the GET variant. In most cases migrating means: 1. Create a matching monitor in the HelloCron dashboard and grab an API key. 2. Point your existing ping calls at HelloCron's endpoint instead of Cronitor's, swapping in the new API key. 3. Leave the rest of the call - status values, params - unchanged. ```diff - curl "https://cronitor.link/p//my-job?state=complete" + curl "https://hellocron.com/ping/my-job?api_key=&status=complete" ``` ## From PostPing, Healthchecks.io, or any other ping-based monitor The pattern is the same regardless of where you're coming from - these tools all work by having your job call a URL on start/success/failure. To switch: 1. Create a monitor in HelloCron and get its ping URL + API key. 2. In your cron wrapper or CI job, replace the old ping URL with HelloCron's, using the [hellocron.sh client](/guides/shell-script/) or plain `curl` against [`GET /ping`](/api/ping-get/). 3. Map your old tool's status/state values onto HelloCron's four states: `run`, `complete`, `fail`, `skip` (see [Event Types & States](/api/event-types/)). ## Migration checklist - [ ] Inventory every job currently pinging the old service (cron, CI, systemd timers, k8s CronJobs). - [ ] Run both services in parallel for a few cycles per job - don't cut over a job until you've seen a `complete` or `fail` ping land in HelloCron. - [ ] Recreate alert routing (email/Slack/webhook) for each monitor before decommissioning the old tool, so you don't have a gap in coverage. - [ ] Once every monitor is confirmed reporting, remove the old service's ping calls and cancel that subscription. --- # Shell Script Client Section: Guides. URL: https://docs.hellocron.com/guides/shell-script/ Summary: Use hellocron.sh for easy integration from any shell script. The bundled `hellocron.sh` client wraps the API calls so you don't write curl by hand. The source lives in the public [hellocron/cli repository on GitHub](https://github.com/hellocron/cli) - audit it, star it, or open an issue there. ## Installation Download the latest client and put it on your PATH: ```bash curl -fsSL https://hellocron.com/hellocron.sh -o /usr/local/bin/hellocron chmod +x /usr/local/bin/hellocron ``` Optional: verify the download against the published checksum. ```bash curl -fsSL https://hellocron.com/hellocron.sh.sha256 sha256sum /usr/local/bin/hellocron ``` Configure once with your ingest key, created in the panel under Settings and API keys: ```bash hellocron configure # asks for the key, nothing else hellocron configure --api-key ck_xxx # or set it without prompting ``` That writes `~/.hellocron.conf` with permissions 600: ```ini api_key=ck_your_ingest_key telemetry_enabled=true default_project= ``` The API address is built into the client, so it is not part of the config. Point the client somewhere else only for a self-hosted or staging setup, with `hellocron configure --advanced` or an `api_url=` line in the config file. A legacy JSON config at `~/.hellocron-config.json` is still read when `.hellocron.conf` is absent. Every ping reports the machine it came from. In a container, where the hostname is a random hex, pin it with a `hostname=` line in the config file or `HELLOCRON_HOSTNAME`. ## Version and updates The download URL always serves the latest client. Updates are on demand, not automatic. ```bash hellocron version # installed version and date hellocron update --check # check whether a newer version exists hellocron update # download, verify checksum, replace (keeps a .bak) ``` `update` pulls from the same URL, verifies the SHA-256 checksum, runs a syntax check, backs up the current file as `.bak`, then swaps it in. It needs `curl`, `sha256sum` and `bash`, and only updates over HTTPS. Version history: [client changelog](/reference/client-changelog/). ## Usage ```bash hellocron ping [options] ``` ### Statuses ```bash hellocron ping my-job run hellocron ping my-job complete hellocron ping my-job fail hellocron ping my-job skip ``` ### Options | Flag | Description | |------|-------------| | `--tags ` | Comma-separated tags | | `--project ` | Project the job belongs to | | `--timeout ` | Expected maximum run time, sent with the `run` state | | `[message]` | Free text after the state becomes the message (for example the error) | `ping` sends one state and nothing else. Duration, exit code and captured error output come from `run`, which wraps the command and sends both pings for you: ```bash hellocron run db-backup --tags nightly pg_dump mydb > /tmp/backup.sql ``` ### Example with separate pings ```bash hellocron ping db-backup run pg_dump mydb > /tmp/backup.sql EXIT=$? if [ $EXIT -eq 0 ]; then hellocron ping db-backup complete else hellocron ping db-backup fail "pg_dump exited with $EXIT" fi exit $EXIT ``` ## Checking your setup Run `doctor` to verify that everything is configured correctly: ```bash hellocron doctor # checks config, API URL, key, connectivity hellocron doctor --ping # additionally sends a real test ping (state: skip) ``` It checks: HTTP tool availability (curl/wget), config file and its permissions, API URL and key, temp directory, API reachability (`/health`) and crontab access. Exit code is `0` when everything is OK, `1` when problems are found. ## Using in Docker Mount the script and config into your container: ```yaml volumes: - ./client/hellocron.sh:/usr/local/bin/hellocron:ro - ./client/.hellocron.conf:/root/.hellocron.conf:ro ``` --- # Uptime badge for your README Section: Guides. URL: https://docs.hellocron.com/guides/uptime-badge/ Summary: Embed a live status badge from a HelloCron status page in a README, wiki or docs site. No API key, no JavaScript, cacheable SVG. Every enabled status page serves a badge as an SVG at a stable URL. Paste it in a README and readers see whether the thing you built is up, without clicking anything. ``` https://app.hellocron.com/s//badge.svg ``` Markdown, linking the badge back to the full status page: ```markdown [![Status](https://app.hellocron.com/s/acme-status/badge.svg)](https://app.hellocron.com/s/acme-status) ``` The panel generates this snippet for you: open the status page in **Status pages → your page**, scroll to **Uptime badge** and copy the field. ## What it shows and what it does not The badge is derived from the status page it belongs to, and shows nothing beyond what that page already shows publicly. There is no key, no token and no separate privacy setting, because there is no separate decision to make: if the monitor is published on a public status page, its badge is public too. A disabled status page returns 404, identical to a slug that never existed. ## Options | Parameter | Values | Effect | |---|---|---| | `monitor` | display name of one monitor on the page | Badge for that monitor instead of the whole page | | `metric` | `status` (default), `uptime30`, `uptime90` | Show a status word or an uptime percentage | | `label` | any text, up to 40 characters | Replaces the left half of the badge | | `style` | `flat` (default), `flat-square` | Rounded or square corners | ```markdown ![Backups](https://app.hellocron.com/s/acme-status/badge.svg?monitor=Nightly%20backup&metric=uptime30&label=backups) ``` Two behaviours worth knowing, because both are deliberate: - **A misspelled `monitor` name returns 404**, rather than a badge reading "unknown". A typo should be visible the day you make it, not six months later when someone notices the badge has been meaningless the whole time. - **`metric=uptime30` on a monitor with no data falls back to the status word.** A percentage is not invented from an empty sample. For the same reason there is no page-wide uptime percentage: averaging monitors with wildly different traffic produces a number that looks precise and means nothing. ## Colours | Colour | Status | Uptime | |---|---|---| | Green | operational | 99% and above | | Amber | degraded | 95% to 99% | | Red | down | below 95% | | Grey | unknown, nothing reported yet | no data | ## Caching The badge sends `Cache-Control: public, max-age=60` and an `ETag`. GitHub and most README hosts proxy images through their own cache, so expect up to a few minutes of delay before a status change shows up in a README even though the status page itself is already current. That is a property of the proxy, not of the badge. The SVG is self-contained: no external fonts, no scripts, no remote images. It renders the same in a README, a wiki, a docs site or a plain `` tag. --- # Shell client changelog Section: Reference. URL: https://docs.hellocron.com/reference/client-changelog/ Summary: Version history of the hellocron.sh shell client. The download at `https://hellocron.com/hellocron.sh` always serves the latest version listed below. Older entries are history, they are not kept as separate downloads. Run `hellocron update` to move to the latest, or `hellocron version` to see what you have installed. ## v1.5.4-260914 (unreleased) - `run` preserves the job's original umask. ANSI colors and other control characters no longer produce invalid ping JSON. - `discover` preserves quoted hashes and backslash escapes, runs environment assignments through a shell, and quotes project names and client paths safely. - Options missing their values fail promptly. `configure` returns a failure when the configuration cannot be written or secured. ## v1.5.3-260913 (current) Released 2026-09-13. The client now tells you about the plan limit, without ever failing a job over it. - Quota state is read from the response headers of every ping and reported on stderr: approaching the limit, over it, or monitoring suspended, each with the date the quota resets. Running out of quota never changes the exit code and never fails a job. That is the whole point: a ping comes from a curl line in a crontab, so answering it with an error would make cron treat a job that ran perfectly as failed and mail its owner about it. A billing problem must not become a production incident. - Messages from the ping request reach the terminal at all. They used to be captured into a variable nobody read, so every warning the request produced disappeared silently. - Nothing changes for self-hosted installs or older servers: no quota headers means no messages. ## v1.5.2-260912 Released 2026-09-12. `discover` understands the crontabs that actually exist, and `doctor` answers whether the client is current. - `doctor` reports whether the installed client is the current one. It asks for the published version, names it when a newer one exists and tells you to run `update`; a pending update is a warning, not a failed health check. When the download host cannot be reached the line says so instead of claiming either answer. `--no-update-check` skips the request. - Day and month names are accepted: `5 4 * * sun`, `0 8 * * MON` and `30 2 1 JAN *` are ordinary crontab(5) syntax and were being skipped without a word, so the jobs they scheduled were left unmonitored. - A command built out of shell syntax (`&&`, `||`, `;`, a pipe, a redirection, an `if`) is handed to `/bin/sh -c` instead of being executed directly. `run` is not a shell: `test -x /usr/sbin/anacron || { cd / && run-parts /etc/cron.daily; }` used to be monitored up to the first operator only, and the part that did the work ran outside the monitor. A trailing `>/dev/null 2>&1` stays outside, so the client's own output is silenced too. - System crontabs are handled: in `/etc/crontab` and `/etc/cron.d/*` the sixth field is the user to run as, detected from the file name or forced with `--system` / `--user-crontab`. The user stays where cron expects it and no longer becomes the monitor name, so a whole directory of jobs no longer arrives as `root`, `root-5ef365`, `root-913b85`. - Monitor names come from the program that does the work, not from the shell plumbing around it: `run-parts-cron-daily`, `debian-sa1`, `sessionclean` instead of `test`, `command`, `cd`, `if`. Tabs between the schedule fields are handled, and `@midnight` is recognised along with the other nicknames. - Expressions cron would refuse to load are skipped instead of being proposed: Quartz extensions (`0 0 14W * *`, `0 0 * * 6#5`, `LW`), a sixth schedule field, full day names (`friday`), plain typos. A rejected crontab file takes every other job down with it, so a missing proposal is the safer answer. ## v1.5.1-260912 Released 2026-09-12. One question at setup, names you can read in the dashboard. - `configure` asks for the ingest key and nothing else. The API address is built into the client, so a config file holds just the key. `configure --api-key ck_xxx --project name` sets it up without prompting, and `--advanced` still asks for the API URL and ping endpoint for self-hosted or staging installs. - `run` hands the command's output back on the stream it came from. It was captured for the ping and never printed, which silently emptied crontab lines that append to a log file and stopped cron from mailing a failure. - `discover` builds monitor names from the URL or the script instead of the first word on the line: `fakturex-fcron`, not `curl-16f0fd`. Names are sanitised to the character set the API accepts, so a dot in a script filename no longer produces a monitor whose every ping is rejected. A short hash is appended only when two jobs would otherwise share a name. - Prompts show a stub of the stored key instead of the whole thing. - `discover --host-prefix` puts the short hostname in front of every generated name, for one crontab deployed to several servers. Without it names stay per job, because a monitor name cannot be changed later and a host can be renamed. - The reported host can be pinned with `hostname=` in the config file or `HELLOCRON_HOSTNAME`, which matters in containers where the hostname is a random hex. `doctor` prints the host it would report. ## v1.4-260911 Released 2026-09-11. New name, new home. - The script is `hellocron.sh`, downloaded from `https://hellocron.com/hellocron.sh`; `hellocron update` checks that URL. - Config files are `~/.hellocron.conf` and `~/.hellocron-management.conf`; environment variables are `HELLOCRON_API_KEY`, `HELLOCRON_MANAGEMENT_KEY`, `HELLOCRON_PANEL_URL`. - Default endpoints point at `api.hellocron.com` and `app.hellocron.com`. - New `hello:cron` header in `help`, `doctor` and `version`. ## v1.3-260727 Released 2026-07-27. Config as code from the command line. - `hellocron export` downloads every monitor on the account as a single bundle file. - `hellocron apply -f monitors.json` reconciles the account with that file, with `--dry-run` to preview the changes first. Apply never deletes: monitors missing from the bundle are reported as orphaned and left alone. - `hellocron configure --management-key` stores the Management API key in `~/.hellocron-management.conf` (permissions 600), kept **separate** from `~/.hellocron.conf`. The ingest key belongs on every monitored server; the management key can delete monitors along with their history, so the two never share a file. `HELLOCRON_MANAGEMENT_KEY` takes precedence and is the right choice for CI. - Mixing the two keys up is now caught locally with an explanatory message instead of a bare `401`: `apply`/`export` refuse an ingest key (`ck_`), and pings refuse a management key (`mk_`). - `hellocron doctor` reports the management key and the permissions of its config file when present. ## v1.2-260704 Released 2026-07-04. First public release, served at the download URL. - Job lifecycle pings (`run`, `complete`, `fail`, `skip`) and command wrapping with automatic exit-code reporting. - Interactive setup via `hellocron configure`, with configuration stored in `~/.hellocron.conf`. - Cron job discovery via `hellocron discover`: detects existing cron jobs and generates a monitoring config. - Self-update via `hellocron update` (and `update --check`): SHA-256 verification, syntax check, and a `.bak` backup before replacing. - Environment diagnostics via `hellocron doctor`. - Configurable timeouts, verbose mode, telemetry toggle, and default-project support. New releases are added above this entry. --- # Postman Collection Section: Reference. URL: https://docs.hellocron.com/reference/postman/ Summary: Download the HelloCron API collection for Postman. Download the ready-to-use Postman collection with all API endpoints pre-configured. ## Download [**Download hellocron-postman.json**](/hellocron-postman.json) Import into Postman: **File → Import** → select the downloaded file. ## Setup After importing, set the collection variables: | Variable | Value | |----------|-------| | `base_url` | `https://api.hellocron.com` — Ingest API | | `app_base_url` | `https://app.hellocron.com` — panel, Management API | | `api_key` | Ingest API key (`ck_...`) from **Settings → API key** | | `management_api_key` | Management API key (`mk_...`) from **Settings → API key** | | `monitor_uuid` | Monitor uuid for get/update/delete requests (copy from List monitors) | Bearer auth is configured per scope: Ping/Health requests use `api_key`, the Monitors folder overrides it with `management_api_key`. Each API accepts only its own key. ## Included requests ### Health & Ping (Ingest API, `base_url`) | Request | Description | |---------|-------------| | `GET /health` | API health check (no auth) | | `POST /ping`, Job started | Send `status: run` when a job begins | | `POST /ping`, Job completed | Send `status: complete` on success | | `POST /ping`, Job failed | Send `status: fail` on error | | `POST /ping`, Job skipped | Send `status: skip` for maintenance windows | | `GET /ping/{monitor}` | Query-param variant for crontab one-liners, IoT, CI | ### Management API (`app_base_url`) | Request | Description | |---------|-------------| | List monitors | `GET /api/v1/monitors`, optional `?kind=` filter | | Get monitor | `GET /api/v1/monitors/{uuid}` | | Create ping monitor / HTTP check / SSL check | `POST /api/v1/monitors` with a manifest body | | Update monitor | `PUT /api/v1/monitors/{uuid}` (full manifest, ping name immutable) | | Delete monitor | `DELETE /api/v1/monitors/{uuid}` — always `403`, deletion is panel-only by design | See [Management API](/api/monitors/) for the manifest format and error codes. --- # Swagger UI Section: Reference. URL: https://docs.hellocron.com/reference/swagger/ Summary: Interactive API explorer. Test endpoints directly from the browser. --- # Features Section: Product. URL: https://docs.hellocron.com/product/features/ Summary: Full HelloCron feature list grouped by module - cron monitoring, HTTP uptime, SSL checks, alerts, API and integrations. ## Cron / Heartbeat monitoring You send an HTTP POST with a JSON payload. We handle the rest. - **Three lifecycle states:** `run` (job started), `complete` (success), `fail` (error). Plus optional `skip` (cycle intentionally skipped, e.g. weekend). - **Heartbeat-only mode.** Skip `run`/`complete`, just have the job ping once every X seconds. No ping = alert. - **Expected interval + grace period.** Tell us "this job runs hourly, 5 minute grace". HelloCron detects missed runs automatically. - **Duration tracking.** Every `complete` ping carries a `duration` in seconds, so you spot slowdowns early. - **Exit code + stderr capture.** With `fail` you can send `exit_code` and `error_output` (up to 64KB of stderr). The dashboard shows what blew up. - **Tags + project metadata.** Group monitors. Multi-tenant via tags (great for agencies). - **State transitions audit.** Every event has timestamp, host, source. CSV export, date filtering. ## HTTP uptime checks Our built-in scheduler hits your endpoints for you. - **Configurable interval.** 30s / 60s / 5min / 15min / 1h (depends on plan). - **Expected status codes.** Default 2xx-3xx. Require a specific 200 or a range like 200-299. - **Response time threshold.** Alert when response time > N ms (for N consecutive checks). - **Retry logic.** 3 attempts before flagging "down" (protects against flaky networks). - **Methods:** GET, POST, HEAD. Custom headers, custom body, basic auth, bearer tokens. - **Body content assertion.** "Response must contain string X" or "must not contain string Y". - **Multi-region (planned).** Today we probe from a single EU location; multi-region is planned. ## SSL certificate alerts - **Daily check** of every monitored domain. - **Multi-stage warnings:** 30 days / 14 days / 7 days / 1 day before expiry. - **Cert chain validation.** Detects expired intermediate cert, mismatched CN. - **Wildcard support.** `*.hellocron.com` treated as its own check. - **Bypass warning** for cert managers (Let's Encrypt auto-renewal). ## Alerts and integrations | Channel | Plan | |---|---| | Email | every plan | | Webhook (custom HTTP POST) | all plans | | Slack | Pro+ | | Telegram | all plans | | Discord | all plans | | PagerDuty | Business | | Teams / others | via webhook + your own bridge | - **Alert routing.** Per monitor + per tag + per project. Backup channel if primary fails. - **Quiet hours.** Mute alerts on weekends / overnight (per channel). - **Grouped alerts.** Multiple jobs failing at once? One message, not spam. - **Re-alerting.** Repeat alert every X minutes until acknowledged. - **Resolved notifications.** Notify when a monitor recovers to "ok". ## Dashboard - **Live event stream.** Every ping visible within seconds of arrival. - **Timeline view.** All monitors side-by-side, colour-coded by state. - **Failure analytics.** Top failing monitors, average failure rate, time-of-day patterns. - **Slowest jobs.** Duration histogram per monitor, p50 / p95 / p99. - **Health Map.** Grid of every monitor, locate problems at a glance. - **Filters / search.** By tag, project, host, date. ## API - **REST + JSON.** Single `/ping` endpoint, simple payload. - **Bearer token auth.** API key per user, rotation from the panel. - **Rate limiting.** Per-IP + per-user, fair use. - **Swagger UI + Postman collection.** Interactive testing. - **GET pings.** We accept GET pings via query params for legacy systems (cron, healthcheck.sh). ## Data and privacy - **Storage:** encrypted, hosted in the EU (AWS). - **History retention:** 7 / 30 / 90 / 365 days depending on plan. - **API keys hashed in DB.** Plaintext shown once, at generation time. - **Backups at-rest encrypted.** Daily snapshots, 30 day retention. - **GDPR-compliant.** Data export, account deletion on request. - **No self-hosting (by design).** You pay us to run it. That's our job. ## Operations - **Service status page** at `status.hellocron.com`. - **99.95% SLA** on the Business plan. - **Maintenance windows** announced 7 days in advance. --- # Use cases Section: Product. URL: https://docs.hellocron.com/product/use-cases/ Summary: Concrete scenarios where HelloCron earns its keep - solo founder, DevOps lead, agency, SRE. Four real situations where HelloCron pays for itself in the first week. ## 1. Solo founder running a production app **Situation.** You're running a SaaS single-handedly. The database backup runs at 03:00 every night. The invoice generator for customers fires on the 1st of the month. The Stripe webhook handler needs to stay responsive. **Problem without HelloCron.** The backup fails on Wednesday night. You find out on Monday when you go to restore some data. 5 days of lost snapshots. **With HelloCron.** ```bash # backup.sh curl -sf $API_URL/ping -H "Authorization: Bearer $KEY" \ -d '{"event_type":"ping","monitor":"db-backup","status":"run"}' pg_dump my_app | gzip > /backups/$(date +%F).sql.gz curl -sf $API_URL/ping -H "Authorization: Bearer $KEY" \ -d '{"event_type":"ping","monitor":"db-backup","status":"complete"}' ``` No `complete` within 30 minutes of `run` → alert to email + Telegram. You know on Wednesday at 03:30, not Monday at 10:00. **Cost:** $0 on the Free plan (15 monitors included). ## 2. DevOps lead with 150 cron jobs on 12 servers **Situation.** Classic enterprise mix: 8 cron jobs on the database server, 12 on app servers (×4), 20 on ETL workers. All in `crontab -e`, nobody knows what runs where. **Problem without HelloCron.** Someone's `find / -mtime +30 -delete` wiped `/var/log/` along with the recent logs. It takes 6 hours to locate the failing job. **With HelloCron.** - Tag every monitor: `server:db-01`, `team:backend`, `criticality:high`. - Dashboard shows all 150 monitors on one view. - Filter by tag, group by host, sort by `last_event`. - Alert routing: `criticality:high` → PagerDuty (Business), everything else → your Slack channel #cron-alerts. - Health dashboard shows "12/12 servers green" at a glance. Time to diagnose a failing job: from 6h to 6 minutes. **Cost:** $35/mo (Pro, one Slack channel included) or $75/mo (Business if you need more than 150 monitors, unlimited Slack channels or PagerDuty). ## 3. Agency running cron jobs for clients **Situation.** Agency with 18 clients. Each has 5-15 cron jobs. ~200 monitors in total. Client X calls: "weekly report didn't arrive". **Problem without HelloCron.** You log into 5 different dashboards. Or you have no dashboards and grep logs. **With HelloCron.** - Each client = one tag: `client:acme`, `client:wayne-corp`. - Multi-tenant routing: `client:acme` alerts → only their Slack channel. - Per-client report export: "here's a CSV showing your backup ran 28/30 days this month". - Client calls → open dashboard, filter by `client:acme`, see everything in 10 seconds. **Cost:** $75/mo (Business, unlimited monitors). Add $10/mo to each client's invoice as "managed monitoring", the rest is your margin. ## 4. SRE / compliance: audit trail and SLA reporting **Situation.** Company with SOC 2 / ISO 27001 requirements. Auditor asks: "prove your backup ran every day for the past year". **Problem without HelloCron.** `crond` logs are local, rotated monthly, long gone. You have no proof. **With HelloCron.** - Business plan → 365 days of event history. - CSV export for any date range. - Every event has timestamp, host, source IP, payload. - Auditor gets a file: `backups_2025-2026.csv` with 365 `complete` entries per monitor. - Plus: SSL expiry checks show TLS on `api.example.com` never lapsed once. **Cost:** $75/mo (Business). A complete audit trail cheaper than 1 hour of compliance officer time. --- ## Sound familiar? [Sign up and ship your first monitor →](/getting-started/quickstart/) --- # Why HelloCron Section: Product. URL: https://docs.hellocron.com/product/why-hellocron/ Summary: The problem we solve, and when you should reach for HelloCron instead of writing your own monitoring from scratch. ## The problem Your cron job died. You don't know. The client emails in the morning: "why didn't the report arrive?". Every dev/ops person running production systems has been there. A cron sits in `crontab -e`, runs for months, then quietly stops. Reasons: - exit code != 0, but stderr only goes to `/dev/null` - network glitch killed `curl` before it reached the external API - the database died overnight, restart killed the long-running ETL - someone committed a config change and the schedule flipped from `0 * * * *` to `0 0 * * 0` - expired SSL cert on an endpoint used by the script - any timeout, OOM, segfault Every such outage is **hours** before anyone notices. Sometimes **days**, if the effect isn't user-visible. ## Common workarounds and their traps **"I'll build my own monitoring."** And you'll be writing alert rules all weekend. Plus maintaining a metrics stack. Plus deploying an agent on every host. Plus explaining a new query language to the next hire. Monitoring becomes a second product you have to keep alive. **"`tail -f` is enough, I'll see it in the logs if something happens."** You won't. Logs fail overnight and you read them in the morning when the client is already calling. **"There's already a service that does this."** Sure, several. But: expensive at scale, no self-serve for PL/EU teams, pricing changes every year. Our API is straightforward, so moving over later is easy if you ever need to. **"Uptime Robot for uptime, healthchecks.io for crons."** Two tools, two logins, two pricings. Plus neither does SSL alerts and neither has a decent timeline dashboard. ## What HelloCron does One product for three monitoring classes: 1. **Cron jobs / heartbeats.** Send a `run` ping on start, `complete` or `fail` on end. Alert fires when the job doesn't start on time, ran too long, or exited with code != 0. 2. **HTTP uptime checks.** We ping your endpoints. Configurable interval, status code expectations, retry, threshold. Standard stuff. 3. **SSL certificate alerts.** We check expiry dates once a day. We warn 30 / 14 / 7 / 1 days ahead. Everything in one dashboard with an event timeline, CSV export, and a simple REST API. ## Who it's for - **Solo dev / founder** running a production system without an ops team. - **Dev team** with several dozen cron jobs across 3-12 servers, where nobody has time to build a full observability stack. - **Agency** running cron jobs for clients, multi-tenant via tags and separate notifications. - **SRE / compliance** needing 365 days of event history and an audit trail. ## What's next - [Quick start →](/getting-started/quickstart/): first ping in 5 minutes - [Features →](/product/features/): full list per plan --- # HelloCron as a Cronitor alternative Section: Comparisons. URL: https://docs.hellocron.com/compare/cronitor-alternative/ Summary: An honest comparison of HelloCron and Cronitor for cron job monitoring, uptime checks and SSL expiry, including pricing, ping API compatibility and how to migrate without downtime. Cronitor is a well established cron monitoring product, and HelloCron is deliberately compatible with its ping format. If you are already sending pings to Cronitor, switching is mostly a URL and key change, not a rewrite. This page lays out where each tool is stronger so you can decide whether the switch is worth your time. Pricing and limits below were checked in **August 2026**. Both products change their plans, so verify current numbers on the vendor page before making a decision. ## Pricing model is the main difference | | HelloCron | Cronitor | |---|---|---| | Free plan | 15 monitors, checks every 5 min | 5 monitors, checks every 5 min | | Paid entry | $12/mo flat, 40 monitors, checks every 60 s | $2 per monitor per month | | Mid tier | $35/mo, 150 monitors, 5 team members | $2/monitor + $5 per dashboard user | | Top tier | $75/mo, unlimited monitors and team members | Enterprise, from $6,000/year | | Extra seats | included in the plan | $5/month per user | | Branded status page | included from $35/mo | $25/month add-on | Cronitor prices per monitor and per user, which is predictable when you have ten monitors and one person, and less predictable when a team grows or a service sprawls into fifty checks. HelloCron prices per plan, so the bill does not move when you add a monitor or a colleague. The practical break-even sits around 15 to 20 monitors. Below that, Cronitor's pay-as-you-go can be cheaper. Above it, and especially with more than one person looking at the dashboard, flat pricing wins. ## Where Cronitor is stronger Being straight about this matters more than winning every row of a table: - **Maturity.** Cronitor has been around far longer, with a larger integration catalogue and a longer public track record. - **Check frequency at the top end.** Enterprise offers checks every 5 seconds. HelloCron goes down to 30 seconds on Business. - **SSO.** SAML SSO is available as a paid add-on. HelloCron does not offer SSO today, it is planned for 2027. - **SMS and phone alerts.** HelloCron alerts through email, webhook, Telegram, Discord, Slack and PagerDuty, with no SMS or voice channel. ## Where HelloCron is stronger - **Three monitor types in one tool and one bill.** Cron pings, HTTP uptime checks and SSL certificate monitoring share a dashboard, a limit and a price. You are not buying uptime monitoring separately from job monitoring. - **Certificate monitoring goes past the leaf.** HelloCron inspects the full chain, including intermediates, with separate warning and alert thresholds, which catches the case where your certificate is fine but the intermediate that signs it is not. - **Flat, predictable bill.** No per-seat charge, no per-monitor charge, no separate charge to brand a status page. - **Config as code.** Monitors can be declared through a manifest and applied through the [Management API](/api/monitors/), so a repository can be the source of truth. - **Seven interface languages.** English, Polish, German, Spanish, French, Brazilian Portuguese and Ukrainian, in the panel and the documentation. ## Migrating HelloCron accepts Cronitor's ping vocabulary: the same `run`, `complete`, `fail` and `skip` states, the same optional `duration`, `exit_code`, `host` and `msg` fields, and the same `?api_key=` query parameter style. For most jobs the change is one line: ```diff - curl "https://cronitor.link/p//db-backup?state=complete" + curl "https://hellocron.com/ping/db-backup?api_key=&status=complete" ``` Note the field name: Cronitor calls it `state`, the HelloCron ping endpoint calls it `status`. Every other event type in HelloCron uses `state`, so the ping endpoint is the exception, not the rule. See [Event Types & States](/api/event-types/). Run both tools in parallel for a few cycles per job before you cancel anything. The full checklist is in [Migrating to HelloCron](/guides/migration/). ## Try it The free plan covers 15 monitors with no credit card, which is enough to mirror a real workload next to your existing setup and compare the two on your own jobs rather than on a comparison table. [Create an account](https://app.hellocron.com/register) and send your first ping in under a minute with the [quick start](/getting-started/quickstart/). --- # HelloCron as a Healthchecks.io alternative Section: Comparisons. URL: https://docs.hellocron.com/compare/healthchecks-io-alternative/ Summary: How HelloCron compares to Healthchecks.io for cron and heartbeat monitoring, including pricing, HTTP and SSL coverage, self-hosting and how to migrate your existing pings. Healthchecks.io is a focused, well built heartbeat monitor with a genuinely generous free tier and an open source self-hosted edition. If cron pings are the only thing you need and you are happy self-hosting, it is a strong choice and this page will not try to talk you out of it. HelloCron solves a wider problem: the same tool watches scheduled jobs, HTTP endpoints and TLS certificates. This page is about when that difference is worth paying for. Pricing and limits were checked in **August 2026**. Verify current numbers on the vendor page before deciding. ## Pricing | | HelloCron | Healthchecks.io | |---|---|---| | Free plan | 15 monitors of any type | 20 heartbeat checks | | Paid entry | $12/mo, 40 monitors | $20/mo, 100 checks | | Mid tier | $35/mo, 150 monitors | $80/mo, 1,000 checks | | Yearly discount | 20% | 20% | | Self-hosting | not offered | open source, self-hostable | | SMS and phone calls | not offered | credits included on paid plans | On raw check count per dollar, Healthchecks.io is the better deal, and if you need a thousand heartbeats it is not close. The comparison changes when your monitoring is not only heartbeats. ## The real difference: what counts as a monitor A Healthchecks.io check is a heartbeat. Something in your infrastructure has to call a URL. That model is clean and it covers scheduled jobs completely, but it cannot tell you that your public API started returning 500s, or that a certificate expires in nine days, because nothing is calling in to report it. In HelloCron, one limit covers three kinds of monitor: - **Ping monitors** for cron jobs, deploy scripts, ETL runs and workers, the same heartbeat model. - **HTTP checks** that HelloCron runs against your endpoints on a schedule, with status code, response body and response time assertions. - **SSL checks** that inspect the whole certificate chain, including intermediates, with separate warning and alert thresholds. If you currently run Healthchecks.io for jobs and a second tool for uptime, you are paying two bills and watching two dashboards for one question: is production healthy. ## Where Healthchecks.io is stronger - **Self-hosting.** The server is open source and you can run it yourself, which matters if your data cannot leave your infrastructure. HelloCron is a hosted service only. - **Price per check at volume.** 1,000 checks for $80/mo is aggressive. - **SMS, WhatsApp and phone call credits** are included on paid plans. HelloCron has no voice or SMS channel. - **Longevity and a large integration list**, built up over many years. ## Where HelloCron is stronger - **HTTP and SSL monitoring included**, not a separate product or a separate bill. - **Status pages** with your branding, included from the $35/mo plan. - **Config as code** through the [Management API](/api/monitors/) manifest format, so monitors can live in the repository next to the jobs they watch. - **Seven interface languages** in the panel and documentation. - **Alert channels on the free plan**: email, webhook, Telegram and Discord, with Slack from $35/mo. ## Migrating Both products work the same way, so migration is a URL swap. Healthchecks.io uses one opaque URL per check with `/start` and `/fail` suffixes. HelloCron uses one endpoint plus a monitor name and a status: ```diff - curl https://hc-ping.com//start + curl "https://hellocron.com/ping/db-backup?api_key=&status=run" - curl https://hc-ping.com/ + curl "https://hellocron.com/ping/db-backup?api_key=&status=complete" - curl https://hc-ping.com//fail + curl "https://hellocron.com/ping/db-backup?api_key=&status=fail" ``` One practical difference: Healthchecks.io identifies a check by a secret UUID in the URL, HelloCron identifies it by name and authenticates with an API key. That means one key works for every monitor, and monitor names stay readable in your crontab. Keep both running for a few cycles per job before you switch anything off. The full checklist is in [Migrating to HelloCron](/guides/migration/). ## Try it The free plan gives you 15 monitors with no credit card, and those monitors can be any mix of cron pings, HTTP checks and certificates. That is usually enough to run a real comparison alongside your current setup. [Create an account](https://app.hellocron.com/register), then follow the [quick start](/getting-started/quickstart/). --- # HelloCron as an UptimeRobot alternative Section: Comparisons. URL: https://docs.hellocron.com/compare/uptimerobot-alternative/ Summary: How HelloCron compares to UptimeRobot for uptime monitoring, cron job heartbeats and SSL expiry, including what the free plans actually cover and how to run both side by side. UptimeRobot is the best known free uptime monitor in the category, and its free plan is hard to argue with on volume: 50 monitors at a five minute interval. If website uptime is the only thing you need to watch, that is a lot of monitoring for nothing. For a long time the gap was scheduled work: heartbeat monitoring, the thing that catches a backup that never ran, used to be a paid UptimeRobot feature. That changed in mid-2026, and heartbeat monitors are now part of the free plan too. So the honest question is no longer whether you can watch a cron job for free, but how much each tool tells you when one fails. Pricing and limits were checked in **August 2026**. Verify current numbers on the vendor page before deciding. ## What a cron failure looks like in each tool An UptimeRobot heartbeat answers one question: did a request arrive within the expected period. That catches a job that never ran, and it is silent about everything short of that. A HelloCron ping monitor carries state. A job reports `run` when it starts and `complete` or `fail` when it ends, optionally with a duration, an exit code and a message. The alert can therefore tell you whether the job never started, started and died halfway, or finished but took three times longer than yesterday, and the dashboard keeps runtimes over time. The free plan is smaller in raw count, and each monitor carries more information: | | HelloCron free | UptimeRobot free | |---|---|---| | Monitors | 15, any type | 50 | | Check interval | 5 minutes | 5 minutes | | Cron and heartbeat monitoring | included, with run/fail states, duration and exit code | included, arrival-only | | HTTP uptime checks | included | included | | SSL expiry alerts | included, full chain | included | | Alert channels | email, webhook, Telegram, Discord | 5 integrations | | Login seats | 1 | none on free | ## Paid plans | | HelloCron | UptimeRobot | |---|---|---| | Entry | $12/mo, 40 monitors, 60 s | Solo, €9/mo, 10 monitors, 60 s | | Mid | $35/mo, 150 monitors, 5 seats | Team, €31/mo, 100 monitors, 30 s | | Top | $75/mo, unlimited monitors and seats | Scale, €58/mo, 200 to 500 monitors, 15 s | UptimeRobot prices above are annual-billing rates; month-to-month billing is slightly higher. Beyond 500 monitors UptimeRobot moves to a custom Enterprise plan. At high monitor counts of a single type, UptimeRobot is cheaper per monitor. At the point where you want jobs, endpoints and certificates in one place, with a team looking at them, the comparison flips. ## Where UptimeRobot is stronger - **Free plan volume.** 50 monitors for nothing is more than anyone else in the category gives away, and since mid-2026 that includes heartbeat monitors. - **Monitor variety on the network side**: port, ping, keyword checks. HelloCron does HTTP, not raw port checks. - **Scale and speed at the top end.** Plans go to 500 monitors and beyond via Enterprise, with 15 second checks on Scale. HelloCron goes down to 30 seconds on Business. - **SMS and voice** alerting options that HelloCron does not have. ## Where HelloCron is stronger - **Cron monitoring with semantics.** States (`run`, `complete`, `fail`, `skip`), durations, exit codes and messages per run, not just "a request arrived". The failure that costs you data is rarely a job that vanished outright; it is one that started and died halfway, and arrival-only heartbeats cannot see it. - **Certificate chain inspection.** Not just the leaf certificate and its expiry date, but intermediates too, with separate warning and alert thresholds. - **One limit across monitor types.** Fifteen monitors can be fifteen cron jobs, or five jobs plus five endpoints plus five certificates, with no repackaging. - **Config as code** through the [Management API](/api/monitors/), so monitors are reviewable in a pull request instead of clicked together in a UI. - **Flat pricing with seats included**, rather than seats sold separately. ## Running both You do not have to choose immediately, and for a while you probably should not. A sensible split while you evaluate: 1. Leave your website checks on UptimeRobot. 2. Wrap your scheduled jobs with HelloCron pings, reporting start and outcome, and mirror a couple of them as UptimeRobot heartbeats if you want a direct comparison. 3. After a few weeks, look at which alerts actually told you something you needed to know, and how much context each one gave you, then consolidate onto whichever tool that was. Wrapping a job takes two lines around whatever you already run: ```bash curl -sf "https://hellocron.com/ping/db-backup?api_key=$KEY&status=run" pg_dump my_app | gzip > /backups/$(date +%F).sql.gz curl -sf "https://hellocron.com/ping/db-backup?api_key=$KEY&status=complete" ``` If the middle line fails, the third one never runs, HelloCron notices the missing `complete` and alerts you. See [Monitoring Cron Jobs](/guides/cron-jobs/) for the timeout and schedule options. ## Try it [Create an account](https://app.hellocron.com/register), no credit card, and put your noisiest cron job behind a ping first. That is the monitor that pays for itself fastest.