Payloads
Attach the reason a job failed to the ping that reports it, so triage starts with the cause.
Send the reason the job failed along with the failure:
curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/failure \
-H "Content-Type: application/json" \
-d '{
"run_id": "backup-20260801",
"payload": "pg_dump: error: connection to server failed: FATAL: too many connections"
}'curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/failure \
-H "Content-Type: application/json" \
-d '{
"run_id": "backup-20260801",
"payload": "pg_dump: error: connection to server failed: FATAL: too many connections"
}'That line renders inline on the run timeline. The on-call engineer sees the cause in the alert instead of opening a shell to find it.
Only POST carries a payload. GET pings are limited to query-string parameters.
What you can send#
| Field | Where | Limit | What it does |
|---|---|---|---|
payload | POST body | 100 KB Free, 1 MB Pro, 2 MB Business | Any string. Stdout, an error message, or JSON |
run_id | Query string or POST body | 255 characters | Ties this ping to the rest of the run |
duration_ms | POST body | none | Report duration yourself instead of letting Drumbeats compute it |
How Drumbeats decides what to store#
Three rules, in order:
- A JSON body with an explicit
payloadfield stores that field's value. - Any other body stores the whole raw body. This is how the plain-text and
--data-binary @-forms work. - No body stores no payload. The ping still costs 1 beat.
Rule 2 means you can POST a flat JSON object and read it back as a key-value table:
curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/log \
-H "Content-Type: application/json" \
-d '{"processed": 1240, "skipped": 3, "duration_ms": 1820}'curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/log \
-H "Content-Type: application/json" \
-d '{"processed": 1240, "skipped": 3, "duration_ms": 1820}'Common shapes#
OUTPUT=$(python job.py 2>&1)
EXIT=$?
EVENT=$([ $EXIT -eq 0 ] && echo "success" || echo "failure")
curl -X POST "https://api.drumbeats.io/v1/ping/<monitor-id>/$EVENT" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg p "$OUTPUT" --arg r "job-$$" '{payload: $p, run_id: $r}')"OUTPUT=$(python job.py 2>&1)
EXIT=$?
EVENT=$([ $EXIT -eq 0 ] && echo "success" || echo "failure")
curl -X POST "https://api.drumbeats.io/v1/ping/<monitor-id>/$EVENT" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg p "$OUTPUT" --arg r "job-$$" '{payload: $p, run_id: $r}')"python job.py 2>&1 | curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/success \
-H "Content-Type: text/plain" \
--data-binary @-python job.py 2>&1 | curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/success \
-H "Content-Type: text/plain" \
--data-binary @-START=$(date +%s%3N)
/usr/bin/backup.sh
END=$(date +%s%3N)
curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/success \
-H "Content-Type: application/json" \
-d "{\"run_id\":\"backup-$(date +%Y%m%d)\",\"duration_ms\":$((END-START))}"START=$(date +%s%3N)
/usr/bin/backup.sh
END=$(date +%s%3N)
curl -X POST https://api.drumbeats.io/v1/ping/<monitor-id>/success \
-H "Content-Type: application/json" \
-d "{\"run_id\":\"backup-$(date +%Y%m%d)\",\"duration_ms\":$((END-START))}"Use jq to build the JSON rather than string interpolation. A stack trace with a quote or a newline in it will produce invalid JSON otherwise, and the ping fails on exactly the runs you needed it most.
Where payloads live#
| Payload size | Stored | Read speed |
|---|---|---|
| Up to 10 KiB | Entirely in the primary database | Renders inline, instantly |
| 10 KiB up to your plan limit | First 10 KiB in the database, the full copy in object storage | Inline preview is instant, the full body loads on demand |
| Over your plan limit | Truncated to the plan limit, then stored as above | The bytes past the limit are gone |
Record progress on a long job#
The log event stores a payload without touching monitor status. On a multi-phase job it turns "the run hung" into "the run hung during the transform".
Each log costs a beat. Keep them on jobs where the phase actually matters during triage, and drop them once a job is stable.
What lands on the run timeline#
Every ping, including log pings, adds one row: the event name, the time Drumbeats received it, the run_id, the duration when known, the payload or a link to the full copy, and the source IP and user agent.
Each monitor keeps its most recent rows and drops older ones. The per-monitor default is 200, tunable from 10 to 1000, and your plan caps how much history is retained overall.
Run one script against several environments#
The slug URL form keeps the monitor name stable and swaps only the project:
Next#
Ping API for events, methods, and error codes. Scheduled pings and event-driven pings for the patterns that use payloads. Beats and usage for what the bytes cost.