API reference
Base URL https://dev.tickingora.com/api/v1 · Tickingora Management API 1.0.0 ·
openapi.yaml · openapi.json
Tickingora is API-first: everything you can configure in the dashboard wizard you can do with this API — with exactly the same validation, plan limits and scheduling engine.
- Authenticate with an API key:
Authorization: Bearer <api-key>(create keys in Settings → API keys). Keys carry scopes:monitors:read,monitors:write,incidents:read. - All times are UTC in ISO 8601 (
2026-10-26T05:00:00Z). Schedules are interpreted in the monitor'stimezone. - Errors always look like
{"error": {"code": "...", "message": "...", "details": {...}}}. - The secret Heartbeat
ping_urlis shown only once — when a monitor is created or its token rotated. Tokens are stored hashed; a lost URL can only be replaced (rotate-token). - Give monitors a stable
external_id(e.g.production:nightly-backup) to find them later and to make repeated set-up runs safe;Idempotency-Keyprotects single requests (24 h).
Account
GET /account
Current account, plan limits and usage · any scope
Works with any scope. Useful before creating monitors (check remaining capacity).
| Status | Description | Body |
|---|---|---|
200 |
Account details. | Account |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
Monitors
GET /monitors
List monitors
· scope monitors:read
| Parameter | In | Type | Description |
|---|---|---|---|
external_id |
query | string | Find a monitor by its external_id. |
type |
query | string | |
status |
query | MonitorStatus | |
limit |
query | integer | Page size (default 50). |
cursor |
query | string | The next_cursor value from the previous page. |
| Status | Description | Body |
|---|---|---|
200 |
A page of monitors, ordered by id. | Monitor |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
422 |
VALIDATION_ERROR — details lists the invalid fields or query parameters. |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
POST /monitors
Create a Heartbeat or HTTP Check monitor
· scope monitors:write
Send Idempotency-Key to make retries safe: repeating the request with the same key and
body returns the original response (header Idempotent-Replayed: true) instead of creating
a second monitor. Keys are kept for 24 hours.
If external_id is already used by another monitor of the account, nothing is created and the
response is 409 MONITOR_ALREADY_EXISTS with details.monitor_id — read or update that monitor
instead. Unlike Idempotency-Key (kept 24 hours), this protection is permanent.
For Heartbeat monitors the response contains heartbeat.ping_url — store it now, it is shown
only once (tokens are stored hashed; use rotate-token to get a new one). A replay of the same
request with the same Idempotency-Key within 24 hours returns the same response, ping URL
included; replays are stored encrypted and deleted when the 24 hours pass.
| Parameter | In | Type | Description |
|---|---|---|---|
Idempotency-Key |
header | string |
Request body — MonitorCreate
{
"type": "heartbeat",
"external_id": "production:bank-import",
"name": "Bank import",
"timezone": "Europe/Warsaw",
"schedule": {
"preset": "daily",
"days": [
1,
2,
3,
4,
5
],
"start": "06:00",
"end": "07:00"
},
"calendar": {
"skip_holidays": true
}
}
{
"type": "http",
"name": "Production API",
"timezone": "Europe/Warsaw",
"schedule": {
"preset": "custom",
"days": [
1,
2,
3,
4,
5,
6,
7
],
"windows": [
{
"start": "07:00"
},
{
"start": "19:00"
}
]
},
"http": {
"url": "https://api.example.com/health",
"expected_status": "2xx",
"headers": [
{
"name": "X-API-Key",
"value": "secret-key"
}
]
},
"recovery": {
"enabled": true,
"interval_minutes": 15
}
}
| Status | Description | Body |
|---|---|---|
201 |
Monitor created (or the stored response of an earlier request with the same Idempotency-Key). |
Monitor |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
Missing scope (FORBIDDEN_SCOPE) or the plan's active monitor limit is reached (PLAN_LIMIT_REACHED). |
Error |
409 |
MONITOR_ALREADY_EXISTS (the external_id is taken; details.monitor_id) or IDEMPOTENCY_IN_PROGRESS (the same Idempotency-Key is still being processed). |
Error |
415 |
The body is not JSON (UNSUPPORTED_MEDIA_TYPE). |
Error |
422 |
VALIDATION_ERROR (details per field) or IDEMPOTENCY_KEY_REUSED (the key was used with a different body). |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
GET /monitors/{id}
Get a monitor
· scope monitors:read
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer |
| Status | Description | Body |
|---|---|---|
200 |
The monitor. | Monitor |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
PATCH /monitors/{id}
Update a monitor
· scope monitors:write
Partial update. Top-level fields and fields inside calendar, http, notifications
and recovery replace the current values; schedule and arrays (e.g. http.headers)
are replaced as a whole. A header sent without value keeps its stored secret.
Schedule changes apply from the next window; history is never rewritten.
The monitor type cannot be changed.
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer |
Request body — MonitorPatch
{
"schedule": {
"preset": "hourly",
"days": [
1,
2,
3,
4,
5
],
"hour_from": 8,
"hour_to": 18,
"minute_start": 0,
"minute_end": 15
},
"notifications": {
"extra_email": "ops@example.com"
}
}
| Status | Description | Body |
|---|---|---|
200 |
The updated monitor. | Monitor |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
409 |
MONITOR_ALREADY_EXISTS — another monitor of the account uses this external_id (details.monitor_id). |
Error |
415 |
The body is not JSON (UNSUPPORTED_MEDIA_TYPE). |
Error |
422 |
VALIDATION_ERROR — details lists the invalid fields or query parameters. |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
DELETE /monitors/{id}
Delete a monitor
· scope monitors:write
Stops monitoring immediately and revokes the ping URL. History is removed together with the plan retention.
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer |
| Status | Description | Body |
|---|---|---|
204 |
Deleted. | — |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
POST /monitors/{id}/pause
Pause a monitor
· scope monitors:write
No windows are expected while paused. An open incident is closed without a recovery e-mail. Idempotent.
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer |
| Status | Description | Body |
|---|---|---|
200 |
The paused monitor. | Monitor |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
POST /monitors/{id}/resume
Resume a paused monitor
· scope monitors:write
Counts towards the plan's active monitor limit. Idempotent.
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer |
| Status | Description | Body |
|---|---|---|
200 |
The active monitor. | Monitor |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
Missing scope (FORBIDDEN_SCOPE) or the plan's active monitor limit is reached (PLAN_LIMIT_REACHED). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
POST /monitors/{id}/rotate-token
Generate a new Heartbeat ping URL
· scope monitors:write
The previous URL stops working immediately. The new URL is returned only in this response — it is not stored in plain text. This is also the way to recover a lost URL.
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer |
| Status | Description | Body |
|---|---|---|
200 |
The new ping URL. | — |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
409 |
UNSUPPORTED_FOR_MONITOR_TYPE — e.g. rotate-token on an HTTP Check. |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
History
GET /monitors/{id}/runs
Run history
· scope monitors:read
Windows (Heartbeat) or checks (HTTP) that already started, newest first, within the plan's history retention (Free: 30 days).
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer | |
status |
query | RunStatus | |
from |
query | string | Only runs scheduled at or after this time. |
to |
query | string | Only runs scheduled before this time. |
limit |
query | integer | Page size (default 50). |
cursor |
query | string | The next_cursor value from the previous page. |
| Status | Description | Body |
|---|---|---|
200 |
A page of runs. | Run |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
422 |
VALIDATION_ERROR — details lists the invalid fields or query parameters. |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
GET /monitors/{id}/incidents
Incident history
· scope incidents:read
| Parameter | In | Type | Description |
|---|---|---|---|
id required |
path | integer | |
status |
query | string | |
limit |
query | integer | Page size (default 50). |
cursor |
query | string | The next_cursor value from the previous page. |
| Status | Description | Body |
|---|---|---|
200 |
A page of incidents, newest first. | Incident |
401 |
Missing, invalid or expired API key (UNAUTHENTICATED). |
Error |
403 |
The key lacks the required scope (FORBIDDEN_SCOPE). |
Error |
404 |
The monitor does not exist or belongs to another account (MONITOR_NOT_FOUND). |
Error |
422 |
VALIDATION_ERROR — details lists the invalid fields or query parameters. |
Error |
429 |
Too many requests (RATE_LIMITED); see Retry-After. |
Error |
Schemas
Error
| Field | Type | Description |
|---|---|---|
error required |
object | |
error.code required |
string — VALIDATION_ERROR, PLAN_LIMIT_REACHED, MONITOR_NOT_FOUND, MONITOR_ALREADY_EXISTS, RATE_LIMITED, UNAUTHENTICATED, FORBIDDEN_SCOPE, IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_IN_PROGRESS, UNSUPPORTED_FOR_MONITOR_TYPE, UNSUPPORTED_MEDIA_TYPE, NOT_FOUND, METHOD_NOT_ALLOWED, HTTP_ERROR, INTERNAL_ERROR | |
error.message required |
string | |
error.details |
object | For validation errors — field path → list of messages. |
Page
| Field | Type | Description |
|---|---|---|
data required |
array | |
next_cursor required |
string | null | |
has_more required |
boolean |
MonitorStatus
Type: string — waiting, healthy, alerting, paused, unknown
RunStatus
Heartbeat: waiting, success, missed, unknown (Tickingora itself was down).
HTTP Check: scheduled, running, success, failed, not_executed (not run on time by Tickingora).
Type: string — waiting, scheduled, running, success, missed, failed, not_executed, unknown
Weekdays
ISO weekdays, 1 = Monday … 7 = Sunday.
Type: array
Time
Type: string
HeartbeatSchedule
Heartbeat windows are half-open [start, end) and may cross midnight. Windows must not
overlap; the Free plan allows at most one window per 60 minutes.
| Field | Type | Description |
|---|---|---|
(one of) |
HeartbeatDailySchedule | |
(one of) |
HeartbeatHourlySchedule | |
(one of) |
HeartbeatCustomSchedule |
HttpSchedule
HTTP Checks run at points in time (no end). The Free plan allows at most one check per 60 minutes.
| Field | Type | Description |
|---|---|---|
(one of) |
HttpDailySchedule | |
(one of) |
HttpHourlySchedule | |
(one of) |
HttpCustomSchedule |
HeartbeatDailySchedule
One window per selected day.
| Field | Type | Description |
|---|---|---|
preset required |
"daily" | |
days required |
Weekdays | |
start required |
Time | |
end required |
Time |
HttpDailySchedule
One check per selected day.
| Field | Type | Description |
|---|---|---|
preset required |
"daily" | |
days required |
Weekdays | |
start required |
Time |
HeartbeatHourlySchedule
A window every hour from hour_from to hour_to (the last hour with a window).
| Field | Type | Description |
|---|---|---|
preset required |
"hourly" | |
days required |
Weekdays | |
hour_from required |
integer | |
hour_to required |
integer | |
minute_start required |
integer | |
minute_end required |
integer | Equal to minute_start = a full-hour window. |
HttpHourlySchedule
A check every hour from hour_from to hour_to at minute_start.
| Field | Type | Description |
|---|---|---|
preset required |
"hourly" | |
days required |
Weekdays | |
hour_from required |
integer | |
hour_to required |
integer | |
minute_start required |
integer |
HeartbeatCustomSchedule
Explicit windows on the selected days.
| Field | Type | Description |
|---|---|---|
preset required |
"custom" | |
days required |
Weekdays | |
windows required |
array of object | |
windows[].start required |
Time | |
windows[].end required |
Time |
HttpCustomSchedule
Explicit check times on the selected days.
| Field | Type | Description |
|---|---|---|
preset required |
"custom" | |
days required |
Weekdays | |
windows required |
array of object | |
windows[].start required |
Time |
Calendar
| Field | Type | Description |
|---|---|---|
skip_holidays |
boolean | Skip Polish public holidays. |
excluded_dates |
array of string |
HeaderInput
| Field | Type | Description |
|---|---|---|
name required |
string | |
value |
string | Required for a new header. Omit on PATCH to keep the stored value. |
HttpInput
| Field | Type | Description |
|---|---|---|
url required |
string (uri) | Public HTTPS URL, port 443 or 8443. Redirects are not followed. |
expected_status |
string | "200" (exactly 200), "2xx" (any 2xx) or a single code such as "204". |
headers |
array of HeaderInput | Extra request headers (Free plan, up to 5). Values are encrypted and never returned. Host, Content-Length, Transfer-Encoding, Connection, X-Forwarded-* and Proxy-* are not allowed. |
HttpPatch
Like HttpInput, but every field is optional; omitted fields keep their values.
| Field | Type | Description |
|---|---|---|
url |
string (uri) | |
expected_status |
string | |
headers |
array of HeaderInput | Replaces the whole list. A header without value keeps its stored secret. |
Notifications
| Field | Type | Description |
|---|---|---|
extra_email |
string | null (email) | One extra recipient besides the account e-mail. It receives alerts only after confirming the address (we send a confirmation e-mail). |
on_failure |
boolean | E-mail when an incident opens (first failure). |
on_recovery |
boolean | E-mail when the monitor recovers. |
Recovery
Extra checks after a failure until the service responds correctly.
| Field | Type | Description |
|---|---|---|
enabled |
boolean | |
interval_minutes |
integer | null — 15, 30, 60, null | Free plan: 15, 30 or 60. Required when enabled. |
ExternalId
Your stable technical identifier, unique in the account (e.g. production:nightly-backup). Use it to find the monitor later and to make set-up scripts safe to re-run.
Type: string|null
MonitorCreate
Pick the variant by type: Heartbeat monitors have no http/recovery; HTTP Checks require http.
| Field | Type | Description |
|---|---|---|
(one of) |
HeartbeatMonitorCreate | |
(one of) |
HttpMonitorCreate |
HeartbeatMonitorCreate
| Field | Type | Description |
|---|---|---|
type required |
"heartbeat" | |
external_id |
ExternalId | |
name required |
string | |
description |
string | null | |
timezone |
string | IANA time zone; defaults to the account time zone. |
schedule required |
HeartbeatSchedule | |
calendar |
Calendar | |
notifications |
Notifications |
HttpMonitorCreate
| Field | Type | Description |
|---|---|---|
type required |
"http" | |
external_id |
ExternalId | |
name required |
string | |
description |
string | null | |
timezone |
string | IANA time zone; defaults to the account time zone. |
schedule required |
HttpSchedule | |
calendar |
Calendar | |
http required |
HttpInput | |
notifications |
Notifications | |
recovery |
Recovery |
MonitorPatch
Any subset of the monitor's fields. Use the schedule variant of the monitor's type;
http and recovery are accepted only for HTTP Checks. type cannot be changed.
| Field | Type | Description |
|---|---|---|
external_id |
ExternalId | |
name |
string | |
description |
string | null | |
timezone |
string | |
schedule |
any | |
calendar |
Calendar | |
http |
HttpPatch | |
notifications |
Notifications | |
recovery |
Recovery |
Monitor
| Field | Type | Description |
|---|---|---|
id required |
integer | |
external_id required |
string | null | Unique per account (database constraint). |
type required |
string — heartbeat, http | |
status required |
MonitorStatus | |
name required |
string | |
description required |
string | null | |
timezone required |
string | |
schedule required |
any | |
calendar required |
object | |
calendar.skip_holidays required |
boolean | |
calendar.excluded_dates required |
array of string | |
http required |
object | null | |
http.url required |
string | |
http.expected_status required |
string | |
http.headers required |
array of object | |
http.headers[].name required |
string | |
http.headers[].has_value required |
boolean | The value is stored but never returned. |
notifications required |
object | |
notifications.account_email required |
string | |
notifications.extra_email required |
string | null | |
notifications.extra_email_status required |
string | null — pending, verified, unsubscribed, null | pending — confirmation e-mail sent, no alerts yet; verified — receives alerts; unsubscribed — the recipient opted out. |
notifications.on_failure required |
boolean | |
notifications.on_recovery required |
boolean | |
recovery required |
object | null | |
recovery.enabled required |
boolean | |
recovery.interval_minutes required |
integer | null | |
heartbeat required |
object | null | |
heartbeat.ping_url required |
string | null | Only in the create response (shown once, stored hashed); otherwise null. |
heartbeat.ping_url_note required |
string | |
last_run required |
object | null | |
last_run.status required |
RunStatus | |
last_run.at required |
string | null (date-time) | |
open_incident required |
null | Incident | |
next_runs required |
array of object | The next five expected windows/checks (holidays, exclusions and DST applied). |
next_runs[].start required |
string (date-time) | |
next_runs[].end required |
string | null (date-time) | |
paused_at required |
string | null (date-time) | |
created_at required |
string (date-time) | |
updated_at required |
string (date-time) |
Run
| Field | Type | Description |
|---|---|---|
id required |
integer | |
kind required |
string — regular, recovery | |
status required |
RunStatus | |
scheduled_start required |
string (date-time) | |
scheduled_end required |
string | null (date-time) | Heartbeat window end (exclusive). |
signal_count required |
integer | Heartbeat signals received in the window. |
attempt_count required |
integer | HTTP attempts made (max 3; recovery checks 1). |
attempts required |
array | null | HTTP Check only (null for Heartbeat) — every attempt as recorded. |
attempts[].number required |
integer | |
attempts[].at required |
string (date-time) | |
attempts[].http_status required |
integer | null | |
attempts[].duration_ms required |
integer | null | |
attempts[].error_type required |
string | null — http_status, timeout, dns, tls, connection, blocked, error, null | |
attempts[].error required |
string | null | Transport error message (secrets redacted); null for HTTP status mismatches. |
last_http_status required |
integer | null | |
last_duration_ms required |
integer | null | |
last_error required |
string | null | |
note required |
string | null | |
finished_at required |
string | null (date-time) | Heartbeat: time of the first signal (or the window end when missed). |
Incident
| Field | Type | Description |
|---|---|---|
id required |
integer | |
status required |
string — open, recovered, closed | |
opened_at required |
string (date-time) | |
closed_at required |
string | null (date-time) | |
close_reason required |
string | null | recovered, paused … |
failed_runs_count required |
integer | |
opened_by_run_id required |
integer | null | |
closed_by_run_id required |
integer | null |
Account
| Field | Type | Description |
|---|---|---|
email required |
string | |
timezone required |
string | |
plan required |
object | |
plan.name required |
string | |
plan.limits required |
object | |
plan.limits.active_heartbeat required |
integer | |
plan.limits.active_http required |
integer | |
plan.limits.min_interval_minutes required |
integer | |
plan.limits.history_days required |
integer | |
plan.limits.max_headers required |
integer | |
plan.limits.recovery_intervals required |
array of integer | |
plan.usage required |
object | |
plan.usage.active_heartbeat required |
integer | |
plan.usage.active_http required |
integer | |
api_key required |
object | |
api_key.name required |
string | |
api_key.scopes required |
array of string | |
api_key.expires_at required |
string | null (date-time) |