CronRadar ingestion API
This is the complete customer-facing HTTP contract for telemetry and framework discovery. Official SDKs wrap these endpoints. The authenticated dashboard uses a separate management API that is not a supported customer integration surface.
- Production v1 base URL:
https://cron.life/api/v1 - Machine contract:
https://docs.cronradar.com/openapi.json - API key format:
ck_app_{application}_{secret} - Content type for sync:
application/json - Official SDK request timeout: 5 seconds
All endpoint paths below are relative to the v1 base URL. Version 1 is additive-only: existing fields, operations, and meanings remain supported, while new fields are optional. A breaking change requires a new major-version base URL and a documented overlap window during which both major versions operate.
The original unversioned routes remain compatibility aliases for deployed consumers: /ping/* maps to /api/v1/ping/*, /api/sync maps to /api/v1/sync, and /api/sync/status maps to /api/v1/sync/status. New integrations and official SDK releases use v1. No retirement date is assigned until consumer migration can be measured and a separate overlap window is announced.
Authentication
Telemetry supports two methods:
- URL path, the SDK-friendly primary form:
/ping/{monitor_key}/{api_key}. - HTTP Basic authentication: API key as the username and an empty password.
Bulk sync and sync status use HTTP Basic authentication only.
Use Basic authentication for manual diagnostics so the key does not enter shell history, proxy logs, or copied URLs:
curl --fail-with-body --silent --show-error \
--user "$CRONRADAR_API_KEY:" \
"https://cron.life/api/v1/sync/status"
API keys are stored as SHA-256 hashes. Plaintext is shown only when a key is created or rotated. Create a different CronRadar application and key for every deployment environment.
Telemetry endpoints
Every telemetry operation accepts GET and POST. POST is recommended for lifecycle events; GET remains supported for simple schedulers and compatibility.
| Event | URL-path authentication | Basic authentication | Result |
|---|---|---|---|
| Heartbeat | /ping/{monitor_key}/{api_key} | /ping/{monitor_key} | Successful completion without duration tracking |
| Start | /ping/{monitor_key}/{api_key}/start | /ping/{monitor_key}/start | Execution is running |
| Complete | /ping/{monitor_key}/{api_key}/complete | /ping/{monitor_key}/complete | Successful terminal result and duration after start |
| Fail | /ping/{monitor_key}/{api_key}/fail | /ping/{monitor_key}/fail | Failed terminal result and immediate incident |
Common parameters
| Parameter | Location | Required | Contract |
|---|---|---|---|
monitor_key | path | yes | Stable non-empty automation key, at most 200 characters; URL-encode it. |
api_key | path | path-auth routes only | Application API key beginning with ck_app_. |
schedule | query | only to create a missing monitor | Standard five-field cron expression. Supplying it makes the request self-registering. |
gracePeriod | query | no | Grace in seconds; minimum 60. |
message | query | fail only | Optional failure context, at most 1,000 characters. Never send secrets, logs, job payloads, or customer records. |
run_id | query | no | Opaque execution identifier shared by start and terminal events, at most 128 characters. Enables truthful concurrent-run correlation. |
attempt | query | no | Zero-based scheduler retry attempt. Diagnostic only; CronRadar never retries customer work. |
Idempotency-Key | header | no | Duplicate-suppression key, at most 128 characters. Identity is monitor + key; a duplicate returns the original ping without reapplying state. Over-long values are ignored. |
idempotency_key | query | no | Header alternative; the header wins when both are present. |
Bounded outcomes on completion
POST /complete may include at most five values under outcomes. Keys use lowercase letters, numbers, and underscores (maximum 64 characters); values must be finite JSON numbers or booleans. Configure matching expectations in automation settings first. Unconfigured keys are accepted but not stored. A configured key that is omitted fails the check.
curl --fail-with-body --silent --show-error --request POST \
--user "$CRONRADAR_API_KEY:" \
--header "Content-Type: application/json" \
--data '{"outcomes":{"records_processed":842,"errors":0,"successful":true}}' \
"https://cron.life/api/v1/ping/nightly-import/complete?run_id=import-2026-07-21"
CronRadar stores only observed-versus-expected numeric or boolean evidence. Never send job arguments, payloads, records, logs, secrets, tokens, or personal data. When an automation has configured outcome checks, heartbeat-only reports have no outcome body and therefore fail those checks as missing; use the lifecycle completion endpoint.
Self-register and record success
curl --fail-with-body --silent --show-error \
--user "$CRONRADAR_API_KEY:" \
--get "https://cron.life/api/v1/ping/daily-backup" \
--data-urlencode "schedule=0 2 * * *" \
--data-urlencode "gracePeriod=300"
{
"status": "ok",
"monitor": "daily-backup",
"pingedAt": "2026-07-21T06:00:00Z",
"warning": null
}
The first request creates the monitor when it is missing. Later requests may omit schedule, but continuing to send it preserves recovery after accidental deletion.
Full lifecycle
run_id="daily-backup-$(date +%s)-$$"
curl --fail-with-body --silent --show-error --request POST \
--user "$CRONRADAR_API_KEY:" \
--get "https://cron.life/api/v1/ping/daily-backup/start" \
--data-urlencode "schedule=0 2 * * *" \
--data-urlencode "run_id=$run_id"
if ./run-backup.sh; then
curl --fail-with-body --silent --show-error --request POST \
--user "$CRONRADAR_API_KEY:" \
--get "https://cron.life/api/v1/ping/daily-backup/complete" \
--data-urlencode "run_id=$run_id"
else
exit_code=$?
curl --fail-with-body --silent --show-error --request POST \
--user "$CRONRADAR_API_KEY:" \
--get "https://cron.life/api/v1/ping/daily-backup/fail" \
--data-urlencode "run_id=$run_id" \
--data-urlencode "message=Backup command exited with code $exit_code"
exit "$exit_code"
fi
The shell example deliberately returns the original job exit code. Monitoring observes job behavior; it must not turn a failed job into a success. Use a different run_id for concurrent executions and reuse it across retry attempts; increment attempt when the scheduler exposes that number. Without a run ID, CronRadar preserves the individual events and labels any pairing as legacy or incomplete evidence.
Successful heartbeat, start, and complete requests return the common success response. Fail returns:
{
"status": "failure_recorded",
"monitor": "daily-backup",
"recordedAt": "2026-07-21T06:00:12Z",
"message": "Explicit failure recorded - alert triggered",
"failureMessage": "Backup command exited with code 1"
}
Framework registry sync
POST /sync registers or reconciles a scheduler's complete recurring-job registry.
curl --fail-with-body --silent --show-error \
--user "$CRONRADAR_API_KEY:" \
--header "Content-Type: application/json" \
--data '{
"source": "internal-scheduler",
"version": "1.0.0",
"mode": "reconcile",
"monitors": [
{
"key": "daily-backup",
"name": "Daily backup",
"schedule": "0 2 * * *",
"gracePeriod": 300
}
]
}' \
"https://cron.life/api/v1/sync"
Request contract
| Field | Required | Contract |
|---|---|---|
source | yes | Stable integration identifier. It scopes authoritative reconciliation. |
version | no | Integration version for diagnostics. |
mode | no | reconcile or omitted. The monitor list is authoritative for this source. |
monitors | yes | Complete current registry for this source. An empty valid list pauses all previously declared monitors for that source. |
monitors[].key | yes | Stable normalized monitor key. |
monitors[].name | no | Human-readable display name. |
monitors[].schedule | no | Five-field cron expression. Invalid schedules are reported per monitor. |
monitors[].gracePeriod | no | Grace in seconds, minimum 60. |
monitors[].metadata | no | Bounded integration metadata. Do not include payloads or sensitive data. |
Reconciliation behavior
- Calls are idempotent for the same registry.
- Monitor identity is application + key. Repeated keys in one registry are upserts where the final declaration wins; concurrent creates are retried as updates.
- Existing keys update name, schedule, grace, and declaration time.
- A valid authoritative request pauses keys from the same source that disappeared; it never deletes history.
- Reappearing keys resume an automatic drift pause when plan capacity exists. A customer manual pause is preserved.
- Any invalid discovered schedule prevents removal processing for that request.
- Capacity overflow is recorded as
created_plan_limited, paused, and returned as a per-monitor error. It does not create an overage or automatic upgrade.
Response contract
{
"source": "internal-scheduler",
"timestamp": "2026-07-21T06:00:00Z",
"created": [{ "key": "daily-backup", "name": "Daily backup", "action": "created" }],
"updated": [],
"unchanged": [],
"removed": [],
"errors": [],
"summary": {
"total": 1,
"created": 1,
"updated": 0,
"unchanged": 0,
"removed": 0,
"errors": 0
}
}
Possible result actions are created, created_plan_limited, updated, unchanged, and paused_removed. HTTP 200 means the registry was processed; inspect errors for monitor-level rejection or capacity outcomes.
Sync status
GET /sync/status returns the authenticated application's non-drill monitors.
curl --fail-with-body --silent --show-error \
--user "$CRONRADAR_API_KEY:" \
"https://cron.life/api/v1/sync/status"
{
"applicationId": "app_abc123",
"totalMonitors": 1,
"monitors": [
{
"monitorKey": "daily-backup",
"name": "Daily backup",
"schedule": "0 2 * * *",
"gracePeriod": 300,
"createdAt": "2026-07-21T05:55:00Z",
"updatedAt": "2026-07-21T06:00:00Z",
"lastPingAt": "2026-07-21T06:00:00Z",
"status": "healthy"
}
],
"timestamp": "2026-07-21T06:01:00Z"
}
Status values are pending, healthy, warning, critical, and paused.
Errors and retry behavior
Error responses use this shape:
{
"error": "MONITOR_NOT_FOUND",
"message": "Monitor 'daily-backup' not found. Provide schedule parameter for auto-registration."
}
| HTTP | Meaning | Safe action |
|---|---|---|
400 | Invalid key, schedule, grace, or request | Correct the request; do not retry unchanged. |
401 | Missing, malformed, revoked, or invalid key | Rotate or correct the secret; do not retry aggressively. |
402 | A new active automation is not allowed by the current trial/plan | Existing automations still record; pause another automation or change plan. |
404 | Application missing, or monitor missing without a schedule | Add the schedule for self-registration or verify the application key. |
429 | Per-key rate limit reached | Wait for Retry-After; retry with bounded backoff and jitter. |
500 | Unexpected service error | Retry with bounded backoff; never block the observed job indefinitely. |
Telemetry limits are 60 requests per minute and 1,000 per hour per API key. Sync is limited to 10 requests per minute. Official SDKs catch network, timeout, 4xx, and 5xx failures and return control to user code; framework integrations reconcile again later.
Security and data boundary
Send monitor keys, schedules, opaque execution identifiers, retry numbers, lifecycle timestamps, and optional bounded failure context. Do not send job arguments, logs, traces, metrics streams, payloads, database records, access tokens, or personal data. The dashboard may store customer-owned HTTP(S) links to a log search, runbook, or source repository; CronRadar does not retrieve their content. Operational ownership, severity, environment, and alert destinations are lightweight management settings: an automation override wins, then its application default, then its team default. Acknowledging an active incident suppresses repeat escalation while detection and recovery notification remain active. Timed manual maintenance resumes monitoring automatically; plan and discovery pauses never do. All production endpoints use HTTPS.