Документация

REST API

Заводите мониторы тем же деплоем, что и сами задачи.

Монитор, заведённый руками, живёт отдельно от задачи, которую сторожит. Через полгода половина мониторов следит за задачами, которых уже нет, а половина новых задач не прикрыта ничем. Лечится это одним: монитор описывается рядом с задачей и создаётся тем же деплоем.

Аутентификация

Ключ выдаётся в настройках воркспейса и показывается один раз: мы храним только его хэш. Передаётся заголовком Authorization.

bash
curl -s https://tickwatch.dev/api/v1/monitors \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

У ключа два уровня доступа: read и write. По умолчанию выдаётся только чтение — ключ, который лежит в CI и умеет удалять мониторы, должен быть осознанным решением, а не значением по умолчанию.

Ограничения

Лимит запросов считается на воркспейс и зависит от тарифа: от 60 запросов в минуту на бесплатном до 1200 на Business. Текущее состояние возвращается заголовками X-RateLimit-Limit, X-RateLimit-Remaining и X-RateLimit-Reset — на них и стоит смотреть, а не подбирать паузы вслепую.

Ошибки

json
{
  "error": {
    "code": "invalid_request",
    "message": "Некорректное cron-выражение",
    "field": "cron_expr"
  }
}
  • 401 unauthorized — ключа нет, он отозван или истёк
  • 403 forbidden — ключу не хватает доступа write
  • 404 not_found — объекта нет либо он принадлежит другому воркспейсу
  • 402 limit_reached — исчерпан лимит тарифа
  • 422 invalid_request — тело запроса не прошло проверку
  • 429 rate_limited — слишком много запросов

Создать монитор

bash
curl -s -X POST https://tickwatch.dev/api/v1/monitors \
  -H "Authorization: Bearer $TICKWATCH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "cron",
    "cron_expr": "0 3 * * *",
    "name": "Ночной бэкап",
    "tz": "Europe/Moscow",
    "grace_sec": 600,
    "max_duration_sec": 3600
  }'

В ответе — созданный монитор вместе с ping_url. Это и есть смысл вызова: адрес нужен немедленно, чтобы подставить его в саму задачу, а не ходить за ним вторым запросом.

json
{
  "id": "9d0f…",
  "name": "Ночной бэкап",
  "state": "new",
  "schedule": {
    "kind": "cron",
    "cron_expr": "0 3 * * *",
    "interval_sec": null,
    "tz": "Europe/Moscow",
    "grace_sec": 600,
    "max_duration_sec": 3600
  },
  "ping_url": "https://ping.tickwatch.dev/4eca85c1-…",
  "last_ping_at": null,
  "created_at": "2026-08-23T01:38:28.918Z"
}

Список и постраничность

bash
curl -s "https://tickwatch.dev/api/v1/monitors?limit=50" \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

# Следующая страница — по курсору из next_cursor.
curl -s "https://tickwatch.dev/api/v1/monitors?limit=50&cursor=MjAyNi0wOC0…" \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

Пагинация курсорная, а не по смещению. Список мониторов меняется под читающим, и при offset клиент, листающий страницы, пропускает записи и видит дубли.

Изменить и удалить

bash
# Поставить на паузу на время планового переезда.
curl -s -X PATCH https://tickwatch.dev/api/v1/monitors/$ID \
  -H "Authorization: Bearer $TICKWATCH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"paused": true}'

# Сменить расписание.
curl -s -X PATCH https://tickwatch.dev/api/v1/monitors/$ID \
  -H "Authorization: Bearer $TICKWATCH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind": "interval", "interval_sec": 900}'

curl -s -X DELETE https://tickwatch.dev/api/v1/monitors/$ID \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

PATCH меняет только переданные поля, но расписание проверяется целиком: недостающие части берутся из текущего состояния монитора. Неизвестные поля отвергаются с 422 — молча проглоченная опечатка в имени поля означала бы монитор с расписанием, о котором автор скрипта не думал.

Запуски и инциденты

bash
# Последние запуски с кодами возврата и хвостом вывода.
curl -s "https://tickwatch.dev/api/v1/monitors/$ID/runs?limit=20" \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

# Что сломано прямо сейчас.
curl -s "https://tickwatch.dev/api/v1/incidents?status=open" \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

# Отметить, что дежурный уже разбирается.
curl -s -X POST https://tickwatch.dev/api/v1/incidents/$INCIDENT/ack \
  -H "Authorization: Bearer $TICKWATCH_TOKEN"

Отметка не закрывает инцидент: закрыть его может только успешный пинг от самой задачи. Она нужна, чтобы остальные не бросались на ту же аварию, и повторный вызов время первой отметки не сдвигает.

Пример: провижининг вместе с деплоем

bash
#!/usr/bin/env bash
set -euo pipefail

API="https://tickwatch.dev/api/v1"
AUTH="Authorization: Bearer $TICKWATCH_TOKEN"
NAME="nightly-report"

# Ищем монитор по имени среди существующих.
existing=$(curl -fsS "$API/monitors?limit=200" -H "$AUTH" \
  | jq -r --arg n "$NAME" '.data[] | select(.name == $n) | .id')

if [ -z "$existing" ]; then
  created=$(curl -fsS -X POST "$API/monitors" -H "$AUTH" \
    -H 'Content-Type: application/json' \
    -d "{\"kind\":\"cron\",\"cron_expr\":\"0 3 * * *\",\"name\":\"$NAME\"}")
  ping=$(echo "$created" | jq -r '.ping_url')
else
  ping=$(curl -fsS "$API/monitors/$existing" -H "$AUTH" | jq -r '.ping_url')
fi

# Подставляем адрес в саму задачу — тем же деплоем.
kubectl create secret generic tickwatch \
  --from-literal=ping-url="$ping" \
  --dry-run=client -o yaml | kubectl apply -f -
REST API · Tickwatch