Heartbeats — API v1 i MCP | Dokumentacja Nodea
Moduł Heartbeats obsługuje monitory typu cron / dead-man-switch: usługa lub zadanie cron musi cyklicznie wywołać publiczny URL ping (/hb/{token}), a pominięcie terminu (interwał + grace) wywołuje alert. Dokument opisuje endpointy REST API v1 oraz narzędzia MCP tego modułu. Publiczny endpoint ping to osobna, nieuwierzytelniona trasa web i nie jest częścią tego API.
Uwierzytelnianie, zakresy i flaga
Bearer token Passport (Authorization: Bearer <token>). Zakresy: monitoring:read (index, show, runs), monitoring:write (create, update, pause, resume), monitoring:delete (usunięcie). Cały moduł bramkowany flagą features:heartbeats.
Własność, widoczność i maskowanie tokenu
Dostęp wymusza HeartbeatPolicy: view = właściciel lub zaakceptowany udział FOREIGN, manage = wyłącznie właściciel. Istniejący, niewidoczny identyfikator zwraca 403, nieznany — 404. Kluczowa zasada bezpieczeństwa: pola token oraz pochodny ping_url są sekretem (z nich wynika URL crona klienta), więc serializują się tylko dla właściciela (przechodzącego politykę manage). Zaakceptowany udział widzi heartbeat, ale nigdy jego tokenu. Token generowany jest raz przy tworzeniu i jest niezmienny — update go nie regeneruje.
API v1 — endpointy
| Metoda | Ścieżka | Scope | Opis |
|---|---|---|---|
| GET | /api/v1/heartbeats | monitoring:read | Lista heartbeatów (własne + zaakceptowane udziały), paginowana. |
| GET | /api/v1/heartbeats/{heartbeat} | monitoring:read | Szczegóły; meta.can_manage. Token tylko dla właściciela. |
| GET | /api/v1/heartbeats/{heartbeat}/runs | monitoring:read | Historia pingów/pominięć, najnowsze pierwsze. |
| POST | /api/v1/heartbeats | monitoring:write | Utworzenie heartbeatu (generuje token). Zwraca 201. Limit planu → 402 (kod plan_limit_exceeded). |
| PUT/PATCH | /api/v1/heartbeats/{heartbeat} | monitoring:write | Aktualizacja name/interval/grace/note. Token niezmienny. |
| POST | /api/v1/heartbeats/{heartbeat}/pause | monitoring:write | Idempotentna pauza (ustawia paused_at). |
| POST | /api/v1/heartbeats/{heartbeat}/resume | monitoring:write | Idempotentne wznowienie (czyści paused_at). |
| DELETE | /api/v1/heartbeats/{heartbeat} | monitoring:delete | Trwałe usunięcie (kaskada historii). Zwraca 204. |
GET /heartbeats — parametry zapytania
search(string, max 255) — dopasowanie po nazwie.status(enum:active|paused).sort(enum:name|interval_seconds|last_ping_at|created_at, domyślniecreated_at).direction(asc|desc).per_page(int 1–100, domyślnie 20),page.
POST/PATCH — parametry ciała
name(string, wymagany, max 255).intervalSeconds(int, wymagany, 60–259200) — oczekiwany interwał pingu.graceSeconds(int, wymagany, 0–86400) — okres karencji dodany do interwału.note(string, opcjonalny, max 5000).notificationGroupsId[](tylko POST) — muszą należeć do użytkownika tokenu (inaczej422). Update nie przyjmuje sync grup.
Kształt odpowiedzi (HeartbeatResource)
Pola: id, name, status (paused→waiting→late→ok), interval_seconds, grace_seconds, note, token (tylko właściciel), ping_url (tylko właściciel), ownership (owner|shared), last_ping_at, deadline_at (dopiero po pierwszym pingu), paused_at, created_at, updated_at. Wpis historii (HeartbeatRunResource): id, heartbeat_id, state, state_name (Success = ping / Failure = pominięty termin), reason, reason_code, created_at.
Kody błędów
401— brak/niepoprawny token;403— scope/polityka;404— nieznany id;422— walidacja lub cudza grupa powiadomień;402— przekroczony limit planu przy tworzeniu (plan_limit_exceeded).
Przykłady — API
Utworzenie heartbeatu (co 5 min, grace 60 s)
curl -s -X POST https://app.nodea.io/api/v1/heartbeats \
-H "Authorization: Bearer $NODEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly backup",
"intervalSeconds": 300,
"graceSeconds": 60,
"note": "cron 0 3 * * *"
}'
Odpowiedź zawiera token i ping_url — jednorazowy moment na podpięcie crona. Skrypt wywołuje potem ping_url po każdym udanym przebiegu.
Lista aktywnych heartbeatów
curl -s "https://app.nodea.io/api/v1/heartbeats?status=active&sort=last_ping_at&direction=desc" \
-H "Authorization: Bearer $NODEA_TOKEN"
MCP — narzędzia
Ten sam model auth/scope co API v1 (ensureScope) i flaga features:heartbeats. Token i ping_url pojawiają się w odpowiedzi tylko gdy wywołujący ma uprawnienie manage (właściciel).
| Narzędzie | Scope | Typ | Opis |
|---|---|---|---|
| heartbeats-list | monitoring:read | read-only | Lista; search, status (active/paused), page, per_page (max 50). Bez tokenu. |
| heartbeat-get | monitoring:read | read-only | Szczegóły; token + ping_url tylko dla właściciela. Param: id. |
| heartbeat-create | monitoring:write | zapis | name, interval_seconds (60–259200), grace_seconds (0–86400), note. Limit planu → błąd. Zwraca token+ping_url. |
| heartbeat-update | monitoring:write | idempotentne | Częściowa aktualizacja name/interval/grace/note. Tylko właściciel. Token niezmienny. |
| heartbeat-set-paused | monitoring:write | idempotentne | Pauza/wznowienie przez paused: true|false. |
| heartbeat-delete | monitoring:delete | destrukcyjne | Trwałe usunięcie; wymaga confirm: true. |
| heartbeat-runs | monitoring:read | read-only | Historia pingów/pominięć; page, per_page (max 50). |
Przykład — MCP (JSON-RPC)
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "heartbeat-create",
"arguments": {
"name": "Nightly backup",
"interval_seconds": 300,
"grace_seconds": 60,
"note": "cron 0 3 * * *"
}
}
}
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "heartbeat-set-paused",
"arguments": { "id": "3af0...uuid", "paused": false }
}
}