Job Monitors — Watches API
Detect failed or missing scheduled jobs with source-scoped heartbeat capabilities.
Watch availability
Watch support may not be available in every hosted environment yet. If the API
returns WATCHES_DISABLED or WATCH_INGRESS_DISABLED, there is no client
setting to change; contact ActionBox support before building the integration
around Watch signals.
A Job Monitor uses the existing Watches API. Your integrations do not need to change. A Watch expects a worker or scheduled job to report progress. If a failure arrives, or the expected signal misses its schedule and grace period, ActionBox creates an ordinary Action for review.
For status transitions, incident recovery, and signal behavior, see Job Monitor Operations.
Workspace owners and admins can use Monitor a job in the console to create a POST-only Watch with its own Source. The one-time heartbeat URL belongs in the job's secret environment. A newly created Watch is waiting for its first real signal; creating it does not prove that the job is connected.
Wrap a scheduled command
Install the ActionBox CLI, store the one-time URL as ACTIONBOX_WATCH_URL in your scheduler's secret environment, and run:
actionbox run -- /opt/jobs/nightly-backup.shThe CLI sends start and then success or fail using POST with a bounded timeout. It preserves the job's exit status if heartbeat transport fails. A failed heartbeat is not retried by this command, so inspect the monitor and its event history when investigating a missed report.
Create with the Python SDK
The Python SDK guide covers installation and Source-key setup.
import os
from actionbox import Actionbox, send_heartbeat
with Actionbox(os.environ["ACTIONBOX_API_KEY"]) as client:
watch = client.watches.create(
name="Nightly backup",
schedule_type="interval",
interval_seconds=3600,
grace_seconds=60,
signal_method="post",
)
heartbeat_url = watch.heartbeat_url
if heartbeat_url is None:
raise RuntimeError("ActionBox did not return a heartbeat URL")
send_heartbeat(heartbeat_url, "start")Use send_heartbeat for ping, start, success, or fail. It always sends POST.
The Source is inferred from ACTIONBOX_API_KEY; callers do not need to copy a
separate Source ID into the request.
For a Python job that already owns the heartbeat URL, report around the actual work and preserve the job's failure:
import os
from actionbox import send_heartbeat
url = os.environ["ACTIONBOX_WATCH_URL"]
def report(signal):
try:
send_heartbeat(url, signal, timeout=10)
except Exception:
# Track transport failure separately; do not log the bearer URL.
pass
report("start")
try:
run_job()
except BaseException:
report("fail")
raise
else:
report("success")run_job() represents your own job function. Validate the job's result before reporting success; an exit code alone may not prove that a backup or import is usable.
Capability safety
The raw heartbeat URL is a bearer capability returned only when a Watch is created or its token is rotated.
- Store it in a secret manager.
- Do not log it, place it in source control, or expose it to a browser.
- Prefer
signal_method="post"so link previewers cannot record a signal. - Rotate the token if the capability may have leaked.
- Pause or archive Watches that are no longer expected to report.
Notifications are not health state
Monitor the Watch and Action state from software. Push delivery is best effort and should not be used as proof that an operator saw an alert.
Monitoring guides
If a job is already missing, start with cron troubleshooting. For signaling, grace periods, and recovery, follow the cron monitoring guide.
Backup monitoring explains which checks belong before a success signal and why restore tests need separate monitoring. For scheduled CI jobs, see GitHub Actions schedule troubleshooting.
Capacity and heartbeat traffic
Developer includes 3 Watches, Pro 20, and Team 50 per workspace. Paused Watches count toward capacity; archived Watches do not. Existing Watches above a new limit remain available, but creating another requires available capacity.
New or changed schedules require at least 5 minutes between heartbeats on Developer and 1 minute on paid plans. Developer cron minute fields must leave at least five minutes between entries, including across the hour boundary. Existing schedules can continue unchanged.
Heartbeat signals share a workspace budget: 6 per minute on Developer, 60 on
Pro and Founder, and 150 on Team. Each Watch also allows 6 signals per minute.
These budgets include start, success, failure, and ordinary ping signals.
Spread heartbeat sends over time. On HTTP 429, respect Retry-After and add a
small random retry delay; do not retry in a tight loop. Configure grace periods
to allow for retries. Additional IP limits may also apply.
The latest heartbeat still updates on each accepted ping. Repeated healthy ping history is sampled at most once every five minutes; transitions and run signals remain recorded. Watch history is a monitoring timeline, not a receipt for every healthy heartbeat.