Monitors & schedules
A monitor is either a Heartbeat (your job reports to Tickingora) or an HTTP Check (Tickingora calls your endpoint). Both share the same schedule, calendar and alerting model.
{
"type": "heartbeat",
"name": "Bank statement import",
"description": "MT940 import and payment matching",
"timezone": "Europe/Warsaw",
"schedule": { "preset": "daily", "days": [1,2,3,4,5], "start": "06:00", "end": "07:00" },
"calendar": { "skip_holidays": true, "excluded_dates": ["2026-12-31"] },
"notifications": { "extra_email": "finance@example.com", "on_failure": true, "on_recovery": true }
}
| Field | Required | Notes |
|---|---|---|
type |
yes (create) | heartbeat or http. Cannot be changed later. |
external_id |
no | Your stable technical id, unique in the account, up to 100 characters (A–Z a–z 0–9 . _ : / -), e.g. production:nightly-backup. |
name |
yes | Up to 120 characters; shown in the dashboard and alerts. |
description |
no | Up to 500 characters. |
timezone |
no | IANA name; defaults to the account time zone. The schedule is interpreted in it. |
schedule |
yes | One of three presets (below). |
calendar |
no | skip_holidays (Polish public holidays, default false), excluded_dates (YYYY-MM-DD). |
http |
for http |
See HTTP Checks. |
notifications |
no | One extra_email besides the account e-mail (it receives alerts after confirming the address — see Incidents & alerts); on_failure / on_recovery toggles. |
recovery |
no | HTTP only; see HTTP Checks. |
Unknown fields are rejected with VALIDATION_ERROR, so a typo such as "shedule" never silently falls back to a default.
Finding monitors by external_id
Pick an external_id that names the job, not the moment — production:nightly-backup, acme-shop/invoice-export. Then:
GET /monitors?external_id=production:nightly-backupfinds it;- creating another monitor with the same
external_idreturns409 MONITOR_ALREADY_EXISTSwithdetails.monitor_id— so a set-up script or an agent can run again at any time without creating duplicates; PATCHcan change it (or setnull); deleting a monitor frees itsexternal_id.
The id is not a secret and is shown in the dashboard. Monitors created in the dashboard have no external_id until you set one with PATCH.
Schedules
Days are ISO weekdays: 1 = Monday … 7 = Sunday. Times are HH:MM in the monitor's time zone.
Heartbeat windows are half-open [start, end): a signal at 06:59:59 counts for 06:00–07:00; a signal at exactly 07:00 belongs to the next window (if there is one). HTTP Checks are points in time and have no end.
daily — one window (or check) per selected day
{ "preset": "daily", "days": [1,2,3,4,5], "start": "06:00", "end": "07:00" }
For an HTTP Check omit end: { "preset": "daily", "days": [1,2,3,4,5], "start": "07:00" }.
A Heartbeat window may cross midnight, e.g. "start": "23:30", "end": "00:30"; it belongs to the day it starts on.
hourly — every hour between two hours
{ "preset": "hourly", "days": [1,2,3,4,5], "hour_from": 8, "hour_to": 18, "minute_start": 0, "minute_end": 15 }
Windows 08:00–08:15, 09:00–09:15 … 18:00–18:15. hour_to is the last hour that has a window. For Heartbeats, minute_end equal to minute_start means a full-hour window (08:00–09:00, 09:00–10:00, …). HTTP Checks omit minute_end.
custom — explicit times
{ "preset": "custom", "days": [1,2,3,4,5], "windows": [
{ "start": "06:00", "end": "07:00" },
{ "start": "12:00", "end": "12:30" }
] }
Up to 24 windows per day; HTTP Checks give only start for each entry.
Rules enforced on every schedule
- Windows of one monitor must not overlap.
- Free plan: at most one window or check per 60 minutes.
- Each preset accepts only its own fields; others are reported as errors.
Calendar
skip_holidays: trueskips Polish public holidays (New Year, Epiphany, Easter Sunday and Monday, 1 and 3 May, Pentecost, Corpus Christi, 15 August, 1 and 11 November, 24–26 December).excluded_datesadds your own days off.- On excluded days nothing is expected and nothing alerts.
Daylight saving time
Schedules follow wall-clock time in the monitor's time zone, with deterministic rules:
- A start time that does not exist (spring forward) moves forward by the gap — 02:30 becomes 03:30.
- A start time that happens twice (fall back) uses its first occurrence.
- Window length is real time: a 60-minute window is always 60 minutes.
next_runs in every monitor response shows the next five windows (or checks) in UTC, with holidays, exclusions and DST already applied — the quickest way to confirm a schedule.
Updating with PATCH
PATCH /monitors/{id} accepts any subset of the fields above:
- top-level fields and the fields inside
calendar,http,notificationsandrecoveryreplace their current values; scheduleand arrays (such ashttp.headersorcalendar.excluded_dates) are replaced as a whole;- the change applies from the next window — the window in progress and all history stay as they were.
curl -sS -X PATCH https://dev.tickingora.com/api/v1/monitors/42 \
-H "Authorization: Bearer $TICKINGORA_API_KEY" -H "Content-Type: application/json" \
-d '{ "schedule": { "preset": "daily", "days": [1,2,3,4,5,6,7], "start": "01:30", "end": "03:00" } }'
Status
Monitor status |
Meaning |
|---|---|
waiting |
Created or resumed; no window has finished yet. |
healthy |
The last finished window/check succeeded. |
alerting |
An incident is open. |
paused |
Nothing is expected; no alerts. |
unknown |
The last result could not be evaluated because of a Tickingora-side problem. |
Pausing (POST /monitors/{id}/pause) removes upcoming windows and closes an open incident without a recovery e-mail. Resuming counts towards the plan's active-monitor limit. Deleting stops monitoring immediately and revokes the ping URL.
Plan limits (Free)
| Limit | Free |
|---|---|
| Active Heartbeat monitors | 20 |
| Active HTTP Checks | 3 |
| Most frequent schedule | every 60 minutes |
| Extra headers per HTTP Check | 5 |
| Recovery check interval | 15, 30 or 60 minutes |
| Detailed history | 30 days |
The same limits apply to the dashboard and the API. Exceeding one returns 403 PLAN_LIMIT_REACHED; GET /account shows current usage.