Guide
Send cron job notifications from Bash
Use a Bash EXIT trap to send one FYInbox notification after every cron job run. This wrapper preserves the command's exit code, records success or failure for people and agents, and gives retries a stable event identity outside chat.
Wrap the cron command with an EXIT trap
Save this as an executable wrapper, keep the API key in the cron environment or a secret store, and pass the real job as its arguments. The trap runs for both exit code zero and non-zero without replacing the original result.
#!/usr/bin/env bash
set -Eeuo pipefail
: "${FYINBOX_URL:?Set FYINBOX_URL to your FYInbox origin}"
: "${FYINBOX_API_KEY:?Set FYINBOX_API_KEY to a source API key}"
if (( $# == 0 )); then
printf 'Usage: %s COMMAND [ARG ...]\n' "$0" >&2
exit 64
fi
readonly scheduled_run="${FYINBOX_CRON_RUN_ID:-$(date -u +%F)}"
if [[ ! "$scheduled_run" =~ ^[-A-Za-z0-9._:]{1,64}$ ]]; then
printf 'FYINBOX_CRON_RUN_ID contains unsupported characters\n' >&2
exit 64
fi
notify_result() {
local job_status="$1"
trap - EXIT
if (( job_status == 0 )); then
if ! curl --fail-with-body --silent --show-error --max-time 10 \
--request POST \
--url "${FYINBOX_URL%/}/api/v1/notifications" \
--header "Authorization: Bearer $FYINBOX_API_KEY" \
--header "Content-Type: application/json" \
--data-binary @- <<JSON
{"title":"Nightly cron job succeeded","body":"The nightly backup command exited successfully.","severity":"success","source":"nightly-backup","tags":["cron","production"],"deduplicationKey":"cron:nightly-backup:${scheduled_run}:success","metadata":{"scheduledRun":"${scheduled_run}","exitCode":"${job_status}"}}
JSON
then
printf 'FYInbox notification failed; cron exit status remains %s\n' "$job_status" >&2
fi
else
if ! curl --fail-with-body --silent --show-error --max-time 10 \
--request POST \
--url "${FYINBOX_URL%/}/api/v1/notifications" \
--header "Authorization: Bearer $FYINBOX_API_KEY" \
--header "Content-Type: application/json" \
--data-binary @- <<JSON
{"title":"Nightly cron job failed","body":"The nightly backup command exited with an error.","severity":"error","source":"nightly-backup","tags":["cron","production"],"deduplicationKey":"cron:nightly-backup:${scheduled_run}:failure","metadata":{"scheduledRun":"${scheduled_run}","exitCode":"${job_status}"}}
JSON
then
printf 'FYInbox notification failed; cron exit status remains %s\n' "$job_status" >&2
fi
fi
exit "$job_status"
}
trap 'notify_result "$?"' EXIT
"$@"Give the scheduled run one stable identity
0 2 * * * FYINBOX_CRON_RUN_ID="$(date -u +\%F)" /opt/fyinbox-notify /opt/jobs/nightly-backup- Set FYINBOX_CRON_RUN_ID from the scheduled window, not from a random UUID generated on every delivery attempt.
- A retry of the same outcome reuses the same deduplication key; a later scheduled run receives a different date.
- Success and failure have distinct suffixes, so a failed attempt and a later successful retry can both remain reviewable.
Record outcomes without claiming heartbeat monitoring
The wrapper also bounds the notification request to ten seconds and reports delivery failure on stderr without changing the cron command's status. FYInbox is the structured record for reported outcomes; it is not a replacement for job scheduling, logs or missing-run detection.
Primary sources
Last verified .
Frequently asked questions
- Does the producer need a special integration?
- No. The examples use an authenticated HTTPS request, so any script, service or visual workflow that can send HTTP can use the same contract.
- Should credentials be included in notification data?
- No. Keep credentials in the producer's secret store and send only the context needed to understand or locate the event.
- Why send this to FYInbox instead of chat or email?
- FYInbox gives project notifications one structured, reviewable home instead of scattering them through Slack, Telegram and email. Those tools remain useful for conversations and intentional messages.
- Why structure notifications for people and agents?
- People and agents both need stable source, outcome and next-action context. FYInbox keeps that context in one notification record outside conversation streams.
- Does this detect a cron job that never starts?
- No. The EXIT trap can report only after Bash starts the wrapper. Use a heartbeat or dead-man's-switch service when a missing execution must be detected.
- Why preserve the original exit code?
- Cron, a parent scheduler or a retry wrapper may use that code to decide whether the command succeeded. Notification delivery must not turn a failed job into a success or a successful job into a failure.
Keep exploring
Put project notifications in their own inbox
Create an account and move the next notification out of chat and into one inbox for people and agents.