Add a heartbeat to a recurring job
A heartbeat monitors a job that already has its own clock. The job pings after
successful work. Silence beyond the period and grace window becomes a missed
check-in, while the /fail variant reports explicit failure.
Prerequisites
Before using the required tools, check whether they are available. If any are missing, stop and offer the user exactly two choices:
- Connect Crontap MCP at
https://mcp.crontap.com/mcp. MCP access works on every Crontap tier. - Configure
$CRONTAP_CLIENT_IDand$CRONTAP_API_KEYfor the raw API. Raw API access requires Ultra.
Do not silently choose a path or continue until the user selects one.
- Know the job's real maximum interval, including expected jitter.
- Choose a grace window long enough for ordinary delay and runtime.
- Decide which component securely stores the returned ping URL.
Workflow
- Create the heartbeat with the expected period and grace.
- Capture the returned ping URL once and store it as a secret.
- Add a success ping only after the job completes successfully.
- Add a
/failping to the job's handled failure path. - Inspect ping history after deployment and after any incident.
- Rotate the token only for compromise or planned credential rotation.
MCP examples
Create a daily heartbeat with 30 minutes of grace:
{
"tool": "create_heartbeat",
"arguments": {
"name": "Nightly import",
"periodMinutes": 1440,
"graceMinutes": 30,
"emailCooldownMinutes": 60
}
}
The response contains a secret ping URL. Do not echo it into source control, CI logs, support tickets, or later agent messages.
Inspect one UTC day:
{
"tool": "get_heartbeat_pings",
"arguments": {
"heartbeatId": "<heartbeat-id>",
"day": "2026-09-14"
}
}
Rotate after explicit confirmation:
{
"tool": "rotate_heartbeat_token",
"arguments": {
"heartbeatId": "<heartbeat-id>"
}
}
Rotation invalidates both variants of the old URL immediately. Update the job with the newly returned URL before its next deadline.
Job integration
Use an environment variable such as CRONTAP_HEARTBEAT_URL.
run_the_job &&
curl --fail --silent --show-error "$CRONTAP_HEARTBEAT_URL"
On a handled failure, call
"$CRONTAP_HEARTBEAT_URL/fail?msg=bounded-error-summary". Keep messages free
of credentials, personal data, and large stack traces.
REST fallback
REST requires Ultra API access. MCP does not.
curl --fail-with-body https://api.crontap.com/v1/heartbeat \
-X POST \
-H "ClientId: $CRONTAP_CLIENT_ID" \
-H "ApiKey: $CRONTAP_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"name": "Nightly import",
"periodMinutes": 1440,
"graceMinutes": 30
}'
Verification
- Send one test success from the deployed job environment.
- Confirm the heartbeat moves from pending after an accepted ping.
- Exercise a safe failure path and verify a
failevent without exposing the ping URL. - Check that the period plus grace reflects the job's worst normal runtime.
Safety and plan limits
- The ping URL is a credential. Anyone holding it can report activity.
- A heartbeat detects silence but does not start or restart the job.
- Starter heartbeat cadence and count limits differ from paid plans. Let the create response enforce the current account.
- On a plan-limit response, present its four-option ladder and the smallest viable option without inventing prices.
Troubleshooting
- No deadline starts until the first accepted ping.
- Pings while paused record history but do not change deadlines.
- Repeated rapid pings may be rate limited while still returning HTTP 200.
- If the old URL stops working after rotation, that is expected. Deploy the replacement secret.
