Back to Documentation
DocsDMH API — checks & pings

DMH API — checks & pings

DMH API — checks & pings

Monitor cron jobs, backups, CI pipelines, IoT devices — anything that should happen on a schedule — with dead-man's-switch semantics: your job pings DMH; silence past the deadline means failure and DMH alerts you (push, email, and whatever subtask chain the task carries).

For AI-agent integration (Claude, etc.) see the MCP connector — same tokens, different protocol.

1. Get a token

Settings → AI Assistant (MCP) → create a token. The dmh_mcp_… value is shown once — store it like a password. The same token works for both the MCP connector and this REST API.

2. Create a check

curl -X POST https://dmh.syntrope.app/api/v1/checks \
  -H "Authorization: Bearer dmh_mcp_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Nightly DB backup", "period_ms": 90000000}'

period_ms is how often the signal is expected (here: 25 h for a daily job — period + slack). Minimum 600000 (10 min). Optional grace_ms adds slack to the first deadline only. The response contains the check id and its ping_url:

{
  "id": "cmd…",
  "name": "Nightly DB backup",
  "task_type": "DEADMANS_SWITCH",
  "status": "ACTIVE",
  "deadline": "2026-07-20T18:00:00.000Z",
  "period_ms": 90000000,
  "ping_url": "https://dmh.syntrope.app/api/checks/9b2f…/ping"
}

3. Ping from your job

Add one line at the end of the job (so it only runs on success):

# cron
0 3 * * * /opt/backup.sh && curl -fsS "https://dmh.syntrope.app/api/checks/9b2f…/ping"

GET, POST and HEAD all work. Every successful ping re-arms the timer to now + period_ms. Responses:

  • 200 {"ok":true,"rearmed":true,"newStartAt":…} — timer re-armed.
  • — check is paused; the ping is accepted (exit code 0 — your cron won't break) but nothing re-arms.

DMH (Dead Man's Hand) — Watchdog timer and postponed reminder system

200 {"ok":true,"rearmed":false,"reason":"not-active"}
  • 404 — unknown or disabled ping URL.
  • The ping URL is a capability: anyone holding it can only re-arm the timer — never read the task, change it, or trigger the alert. Rotate it any time (below); pings are rate-limited per IP.

    4. Everything else

    All routes need the Authorization: Bearer dmh_mcp_… header.

    Method & pathWhat it does
    GET /api/v1/checksList your Watchdog + Healthcheck tasks (no ping URLs)
    POST /api/v1/checksCreate a check (body: name, period_ms, grace_ms?)
    GET /api/v1/checks/:idOne check, including ping_url
    DELETE /api/v1/checks/:idDelete the check
    POST /api/v1/checks/:id/pausePause (pings answer rearmed:false)
    POST /api/v1/checks/:id/resumeResume; deadline re-arms from now
    POST /api/v1/checks/:id/ping-keyEnable or rotate the ping URL
    DELETE /api/v1/checks/:id/ping-keyDisable the ping URL
    GET /api/v1/checks/:id/log?limit=50Trigger journal (pings, probes, failures)

    Existing tasks created in the app work too: any Watchdog or Healthcheck can get a ping URL via POST /api/v1/checks/:id/ping-key.

    Notes

    • The journal records PING_RECEIVED entries (at most one per 5 minutes per task — the timer still re-arms on every ping).
    • Failure behavior is the task's own: when the deadline passes, the task fires exactly like any Watchdog/Healthcheck — push notification and its configured subtask chain.
    • Timestamps are ISO-8601 UTC; durations are milliseconds.