Skip to content

HTTP check-ins (curl)

Report runs from shell cron, CI or any language without an SDK with one curl command: start, finish, heartbeat.

Markdown
On this page

Anything that can make an HTTPS request can report runs: a shell cron line, a CI step, a PHP script, a Go binary without an SDK. HTTP check-ins use the same URL format as Sentry's crons HTTP API, so existing scripts keep working with a Belvador DSN.

The check-in URL#

Text
https://ingest.belvador.dev/api/<project-id>/cron/<monitor-slug>/<public-key>/

<project-id> and <public-key> come from the project's DSN (https://<public-key>@…/<project-id>). The Monitors page shows the full URL for each monitor, already filled in. Treat it like the DSN: it can send data to your project but cannot read anything.

Report a run with a start and a finish#

Pick one id per run (32 hex characters) and send it with both requests, so Belvador can measure the duration and notice a run that started but never finished.

Terminal
ID=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')curl -fsS -m 10 --retry 5 -o /dev/null "https://ingest.belvador.dev/api/<project id>/cron/nightly-invoices/<public key>/?status=in_progress&check_in_id=$ID" || true

When the job succeeds:

Terminal
curl -fsS -m 10 --retry 5 -o /dev/null "https://ingest.belvador.dev/api/<project id>/cron/nightly-invoices/<public key>/?status=ok&check_in_id=$ID" || true

When it fails:

Terminal
curl -fsS -m 10 --retry 5 -o /dev/null "https://ingest.belvador.dev/api/<project id>/cron/nightly-invoices/<public key>/?status=error&check_in_id=$ID" || true

A shell example that reports both cases:

Terminal
if ./nightly-invoices.sh; then STATUS=ok; else STATUS=error; ficurl -fsS "$URL?status=$STATUS&check_in_id=$ID"

Or: a single heartbeat#

When the work cannot report a start — a health loop, a worker that pings every few minutes — send one ok when it is done. Use an Every N minutes/hours monitor for this.

Terminal
curl -fsS -m 10 --retry 5 -o /dev/null "https://ingest.belvador.dev/api/<project id>/cron/nightly-invoices/<public key>/?status=ok" || true

Query parameters#

ParameterValues
statusin_progress, ok, error (required)
check_in_id32 hex characters; the same id on the start and finish of one run
environmente.g. production (default) or staging
durationseconds, if you measure it yourself
releaseyour app's version
outcome + reasonwith status=ok: skipped (nothing to do, healthy) or unknown (ended, effect unknown — Needs review); reason is a short code such as nothing_due
run_id, attempt, will_retrygroup retries into one run: the same run_id on every attempt, attempt from 1, will_retry=true on a failed attempt your queue will repeat

A finish without check_in_id closes the newest open start of that monitor.

A POST with a JSON body can also carry monitor_config — the same settings as withMonitor options, in Sentry's names (schedule, timezone, checkin_margin, max_runtime, failure_issue_threshold, recovery_threshold) — to create or update the monitor from the script.

Answers#

StatusMeaning
202 with {"id": "…"}Accepted; id is the check-in id
400Invalid slug, status or body
401Unknown or inactive key, or the key belongs to another project
403The workspace does not accept data right now
413Body over 100 KiB
429Too many check-ins: at most 60 per monitor and environment per minute, plus a monthly plan limit. Respect Retry-After.

Rules#

  • Never call this URL from a web page: browsers' check-ins are refused, and the key would be visible to every visitor.

  • curl -fsS fails quietly on errors, so a Belvador outage never fails your job. Do not make your job depend on the check-in succeeding.

  • If a check-in is refused for rate limits, the monitor shows Not observable rather than Missed.

Spotted something wrong or missing? Tell us: hello@belvador.dev