For AI coding agents
This page is written for coding assistants (and the people prompting them) that add monitoring to a project. Machine-readable entry points: llms.txt, llms-full.txt, openapi.json. Every guide is also available as Markdown: add .md to its URL.
Rules
- Ping after success, never before. The Heartbeat call is the job's last step and runs only when the job succeeded (
&&,set -e,onSuccess,ExecStartPost). A ping at the start of a job reports work that has not happened. A failed ping must never fail the job (… || echo "ping failed" >&2, systemdExecStartPost=-…,rescue(..., report: false),try/except), and error messages must not contain the ping URL. See Heartbeat. - Give every monitor an
external_idderived from the project and job (acme-shop:invoice-export). It is unique in the account and permanent: running the set-up again — even months later — returns409 MONITOR_ALREADY_EXISTSwithdetails.monitor_idinstead of a duplicate. Check first withGET /monitors?external_id=…. - Also send an
Idempotency-KeyonPOST /monitorsso a retried request (timeout, crash) is safe. It is remembered for 24 hours only —external_idis what prevents duplicates long-term. - Store the
ping_urlas a secret right after creation — it is shown only once (tokens are stored hashed); if the response got lost, retrying the same request with the sameIdempotency-Keywithin 24 hours returns it again. Never commit it, never print it in logs. If the monitor already exists and the job has no URL, callrotate-token(the previous URL stops working). - Make the URL available where the job runs. Cron does not inherit interactive shell variables: use an env file with mode 600 owned by the job user (see Heartbeat), systemd
EnvironmentFile, or the platform's secret store. - Never put the API key in the job. The job needs only its ping URL. The API key belongs to your automation, with the minimum scopes.
- Match the window to reality. The window must contain the time the job finishes. A job starting 02:00 and taking up to 40 minutes needs e.g.
02:00–03:00. - Verify with
?test=1. It proves the job host can reach Tickingora without counting for a window. - Read errors. On
422fix the fields listed inerror.details; on409 MONITOR_ALREADY_EXISTSusedetails.monitor_id(GET, thenPATCHif the configuration differs); on403 PLAN_LIMIT_REACHEDstop and tell the user; on429wait forRetry-After. - Check the result:
next_runsin the response must show the expected windows.
Recipe
# 1. Plan: is there room on the plan?
curl -sS https://dev.tickingora.com/api/v1/account -H "Authorization: Bearer $TICKINGORA_API_KEY"
# 2. Already there?
curl -sS "https://dev.tickingora.com/api/v1/monitors?external_id=acme-shop:invoice-export" -H "Authorization: Bearer $TICKINGORA_API_KEY"
# 3. Create (safe to repeat: 409 MONITOR_ALREADY_EXISTS if it exists)
curl -sS -X POST https://dev.tickingora.com/api/v1/monitors \
-H "Authorization: Bearer $TICKINGORA_API_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: acme-shop:invoice-export:$(date +%F)" \
-d '{"type":"heartbeat","external_id":"acme-shop:invoice-export","name":"Invoice export","timezone":"Europe/Warsaw",
"schedule":{"preset":"daily","days":[1,2,3,4,5],"start":"20:00","end":"21:00"},
"calendar":{"skip_holidays":true}}'
# 4. Save data.heartbeat.ping_url as TICKINGORA_PING_URL where the job runs
# (env file 600 / systemd EnvironmentFile / platform secret store) — shown only once
# 5. Add to the job, after the work:
# php artisan invoices:export && { curl -fsS -m 10 --retry 3 "$TICKINGORA_PING_URL" > /dev/null || echo "Tickingora ping failed" >&2; }
# 6. Verify from the job host, in the job's own environment
curl -fsS "$TICKINGORA_PING_URL?test=1"
Prompt snippet
Add Tickingora monitoring for the
<job>job. Use the Tickingora API (https://dev.tickingora.com/api/v1, key inTICKINGORA_API_KEY) to create a Heartbeat monitor withexternal_id: "<repo>:<job>"(reuse it if it already exists) and anIdempotency-Key, a schedule window that covers when the job finishes, in theEurope/Warsawtime zone, skipping Polish holidays if the job does not run on them. Storedata.heartbeat.ping_urlas theTICKINGORA_PING_URLsecret where the job runs (cron does not see shell variables; use an env file with mode 600) — do not commit it. Call the ping URL withcurl -fsS -m 10 --retry 3only after the job succeeded. Verify with?test=1and show menext_runs. Follow https://dev.tickingora.com/docs/agents.md.
Out of scope today
There is no dedicated MCP server yet — use the REST API and the OpenAPI document.