# illari integration guide illari watches scheduled and triggered runs: cron jobs, systemd timers, Kubernetes CronJobs, CI schedules, worker loops, scheduled AI agents. The job makes one HTTP request each time it runs. If a request is late, missing, or reports a bad result, you get alerted. Create a monitor in the dashboard at https://illari.dev/dashboard, copy its ping URL, and use it from the job. To provision monitors from scripts or CI, use the Management API (below). ## The ping URL Each monitor has one HTTPS URL: `https://illari.dev/ping/`. The key is a 32-character hex string that is both the identifier and the credential. Keep it out of public repos and logs. If it leaks, regenerate it from the monitor page. - `GET`, `POST`, or `HEAD` all count as a check-in. A request body is read only on `POST`. - Extra query parameters are ignored, so appending your own (e.g. `?host=$(hostname)`) is safe. - Set a client timeout: `curl -fsS -m 10`. Add `--retry 3` for transient network failures. Responses: - `200 OK`: recorded. The monitor is Up and the next deadline is recomputed. - `404`: unknown key. - `429`: more than 60 pings in a minute for one monitor. Includes `Retry-After: 60`. A flood guard, not a real limit. ### Minimal crontab example ``` 0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 https://illari.dev/ping/YOUR_KEY ``` The `&&` means the ping fires only if `backup.sh` exited 0. A job that runs but fails then looks silent, which is what you want an alert for. ## Reporting the outcome Add a suffix to say how the run went. - `POST /ping//start`: the run began. Recorded only. It does not satisfy the schedule on its own; you still need a completion ping. The next completion records elapsed time as the run duration. A `start` with no completion within 24 hours is discarded. Set a max runtime on the monitor to be alerted when a run has been going that long with no completion (a hung run). - `POST /ping//`: finished with that code. `0` is success; anything else is a failed run. Use the real shell code (0 to 255). - `POST /ping//fail`: a failed run with no specific code. ``` KEY=YOUR_KEY curl -fsS -m 10 https://illari.dev/ping/$KEY/start if ./run-etl.sh > /tmp/etl.log 2>&1; then code=0; else code=$?; fi tail -c 8000 /tmp/etl.log | curl -fsS -m 10 --data-binary @- \ "https://illari.dev/ping/$KEY/$code" ``` A failed or slow completion still counts as a check-in (the job did run), so the monitor stays Up. The failure shows in the check-in list and, on Pro, fires an alert. ## CLI `illari run` does the wrapping above for you. Node 18+, no dependencies. ``` npm install -g illari # start ping, run the command, completion ping with exit code + output tail illari run --key YOUR_KEY -- /usr/local/bin/backup.sh # key can also come from the environment ILLARI_KEY=YOUR_KEY illari run -- ./nightly-etl.sh # bare one-shot check-in illari ping --key YOUR_KEY ``` Flags: `--url` (full ping URL instead of `--key`), `--base` (default `https://illari.dev/ping`), `--tail ` (output kept for the body, default 10000), `--no-start`. The wrapper exits with the command's own exit code; a failed ping is a warning, not fatal. Source: https://github.com/illari-hq/illari-cli ## Custom metrics Send numbers with the completion ping as form fields or query parameters. Values must parse as numbers; up to 20 per ping; keys match `[a-zA-Z][\w.-]{0,39}`. ``` rows=$(psql "$DATABASE_URL" -tAc "select count(*) from orders") cost=$(cat /tmp/agent_cost) curl -fsS -m 10 -d "rows=$rows" -d "cost_usd=$cost" \ "https://illari.dev/ping/YOUR_KEY/0" ``` On the monitor's Metric rules section (Pro), add rules of two kinds: - Threshold: a fixed condition, `rows is less than 1` or `cost_usd is greater than 5`. Operators: less than, at most, greater than, at least, equals, is not. Fires immediately, no warm-up. - Baseline (anomaly): the value moved far off its own recent norm, direction up, down, or both (`cost_usd spikes`, `bytes drops`). Needs about 8 prior runs of that metric; then flags a value several standard deviations and at least 1.5x off the mean. Either way the alert names the metric, the value, and the rule, and the captured numbers show on the check-in row and in the webhook payload. ## Schedules and timezones A monitor is one of two shapes. - Scheduled: a standard five-field cron expression (`minute hour day-of-month month day-of-week`) plus an IANA timezone (`UTC`, `America/New_York`, ...). Ranges (`1-5`), steps (`*/15`), lists (`1,15`), and the macros `@hourly` `@daily` `@weekly` `@monthly` `@yearly`. illari computes each expected run in that zone with daylight saving handled, so a `0 2 * * *` job does not false-alarm on the changeover weekend. - Open-ended: no cron expression. The monitor expects a ping at least every grace-period seconds. Set the grace period to the longest silence you would tolerate. Good for queue workers and on-demand jobs. ## Grace period A buffer on top of the schedule for jitter and slow starts, in seconds, 0 to 86400, default 300. Deadline is `next expected run + grace` (scheduled) or `last ping + grace` (open-ended). Keep it well under the interval for tight schedules. ## Statuses A worker evaluates every monitor about once a minute. - Pending: created, never pinged. Not evaluated yet. - Up: the last check-in was on time. - Late: the deadline passed with no ping. Fires the first alert. - Down: still silent about 10 minutes after Late. Fires the second alert. Any ping returns the monitor to Up and clears the incident. If an alert had fired, that check-in also sends a recovery notification. ## Status pages Publish a read-only page at `https://illari.dev/s/` (created in Settings) showing the current state of a chosen set of monitors. The link is an unguessable token; the page shows only monitor names, schedules, and states, and refreshes about every 30 seconds. Up to 5 per account. ## Alert channels Every alert emails you (from `alerts@send.illari.dev`). Pro adds Slack, Discord, Telegram, PagerDuty, incident.io, ntfy, Pushover, and a generic webhook (with an optional Authorization header). Channels are account-wide: every enabled one gets every alert. Add and test them in Settings. Repeat Late and failed/slow alerts for one monitor are rate-limited to one every few minutes. Down always goes through. ### Webhook payload ``` POST Content-Type: application/json { "event": "late", // late | down | recovered | hung | failed | slow | metric | metric_anomaly "sentAt": "2026-08-31T03:14:00.000Z", "detail": {}, // failed: { exitCode, output } // slow: { durationMs, baselineMs } // recovered: { from } // hung: { startedAt, maxRuntimeSeconds } // metric: { metric, value, op, threshold } // metric_anomaly: { metric, value, direction, baseline } "monitor": { "id": "…", "name": "nightly-etl", "command": "/opt/scripts/etl.sh", // null unless set "cronExpression": "0 3 * * *", // null for a no-schedule monitor "timezone": "America/New_York", "lastPingAt": "…", "nextExpectedAt": "…" }, "url": "https://illari.dev/dashboard/…" } ``` ## Management API A small REST API for provisioning monitors. Jobs still only call the ping URL; this is for setup and automation (CI, scripts, a coding agent, "monitors as code"). Auth: create a key at https://illari.dev/dashboard/settings (shown once). Send it as `Authorization: Bearer illari_...` on every request. Keys are account-scoped, full-access, and revocable. Base URL: `https://illari.dev/api/v1` - `GET /monitors`: list. Response `{ "data": [ monitor, ... ] }`. - `POST /monitors`: create. Body: `name` (required), optional `command`, `cronExpression`, `timezone` (IANA, default `UTC`), `gracePeriodSeconds` (0 to 86400, default 300), `maxRuntimeSeconds`, `metricRules` (Pro; array of either `{ "kind": "threshold", metric, op, value }` with op one of `lt lte gt gte eq ne`, or `{ "kind": "anomaly", metric, direction }` with direction one of `up down both`). Returns `201` with `{ "data": monitor }` including `pingKey`. - `GET /monitors/`: one monitor as `{ "data": monitor }`. - `PATCH /monitors/`: update any create field, plus `paused` (boolean) and `snoozedUntil` (future ISO 8601 string, or `null` to wake now). Only the keys present in the body change. - `DELETE /monitors/`: delete the monitor and its history. Returns `204`. - `GET /monitors//pings`: recent check-ins, newest first. Query `limit` (1 to 200, default 50) and `before` (ISO 8601). Response `{ "data": [ ping, ... ], "nextBefore": "..."|null }`; pass `nextBefore` as the next `before` to page. Errors: `{ "error": "message" }` with status `401` (missing/malformed/ revoked key), `400` (bad field), `403` (monitor limit reached, or a Pro field on a Free account), `404` (id not visible to this key). ``` curl -fsS -X POST https://illari.dev/api/v1/monitors \ -H "Authorization: Bearer illari_YOUR_KEY" \ -H "content-type: application/json" \ -d '{"name":"nightly-etl","cronExpression":"0 2 * * *","timezone":"America/Chicago","gracePeriodSeconds":600}' ``` Full reference: https://illari.dev/docs/api . Machine-readable OpenAPI 3.1 spec: https://illari.dev/openapi.json . Alert channels are not manageable through the API yet. A Terraform provider is planned on top of this API. ## Plans and limits - Free: 25 monitors, email alerts (including recovery and hung-run notices), cron and timezone scheduling, grace periods, pause, snooze, status badge, 14 days of check-in history. Recording run data (exit code, duration, output) is included; viewing it and alerting on it is Pro. - Pro: $20/month or $204/year. Unlimited monitors (500 fair-use); Slack, Discord, Telegram, PagerDuty, incident.io, ntfy, Pushover, webhook channels; the run-history view of structured run data with failed, duration-anomaly, and custom-metric threshold alerts; 90-day history. Ping rate limit: 60/minute per monitor. Captured body: about 10 KB per ping. ## Monitoring an AI agent run An agent run is a scheduled run like any other. Ping at the end with the exit code, and send cost or tool-call counts as metrics. ``` python agent.py; code=$? curl -fsS -m 10 \ -d "cost_usd=$(cat run_cost.txt)" \ -d "tool_calls=$(cat run_tool_calls.txt)" \ "https://illari.dev/ping/YOUR_KEY/$code" ``` Then set rules: `cost_usd is greater than 5`, `tool_calls is greater than 100`. A missed ping still means the run did not happen; a ping with `cost_usd` over the limit means it ran and overspent.