> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kodostatus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Heartbeat Monitoring

> Monitor cron jobs, workers, and background tasks

Heartbeat monitoring tracks services that can't be pinged from the outside. Your service sends periodic "heartbeat" signals, and we alert you if they stop.

## How It Works

1. Create a heartbeat monitor with an expected interval
2. Your service pings the monitor at regular intervals using your API key
3. If we don't receive a ping within the expected window, we alert you

## Use Cases

* **Cron jobs** - Verify scheduled tasks complete
* **Background workers** - Monitor queue processors
* **Batch jobs** - Track ETL and data pipelines
* **Internal services** - Services behind firewalls

## Creating a Heartbeat Monitor

<Tabs>
  <Tab title="Dashboard">
    1. Go to **Dashboard > Heartbeat**
    2. Click **Add Monitor**
    3. Name your monitor and set the expected interval
    4. Copy the monitor ID
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    kodo heartbeats create \
      --name "nightly-backup" \
      --interval 86400 \
      --grace-period 3600
    ```
  </Tab>
</Tabs>

## Authentication

Heartbeat endpoints require API key authentication via the `X-API-Key` header or `Authorization: Bearer` header. You can use either your organization's API key or a [scoped API key](/api-keys) with the `heartbeat:write` scope.

## Sending Heartbeats

Add a simple HTTP call to your job:

<Tabs>
  <Tab title="Bash">
    ```bash theme={null}
    # At the end of your cron job
    curl -X POST "https://kodostatus.com/api/heartbeat/MONITOR_ID" \
      -H "X-API-Key: YOUR_API_KEY"

    # With status and metrics
    curl -X POST "https://kodostatus.com/api/heartbeat/MONITOR_ID" \
      -H "X-API-Key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"status": "up", "message": "Backup completed"}'
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    // Simple ping
    await fetch('https://kodostatus.com/api/heartbeat/MONITOR_ID', {
      method: 'POST',
      headers: { 'X-API-Key': process.env.KODO_API_KEY }
    });

    // With details
    await fetch('https://kodostatus.com/api/heartbeat/MONITOR_ID', {
      method: 'POST',
      headers: {
        'X-API-Key': process.env.KODO_API_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        status: 'up',
        response_time_ms: Date.now() - startTime,
        message: 'Processed 1,234 records'
      })
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests
    import os

    headers = {'X-API-Key': os.environ['KODO_API_KEY']}

    # Simple ping
    requests.post(
        'https://kodostatus.com/api/heartbeat/MONITOR_ID',
        headers=headers
    )

    # With details
    requests.post(
        'https://kodostatus.com/api/heartbeat/MONITOR_ID',
        headers=headers,
        json={
            'status': 'up',
            'response_time_ms': duration_ms,
            'message': f'Processed {count} records'
        }
    )
    ```
  </Tab>
</Tabs>

## Status Values

The `status` field in the request body supports:

| Value      | Description                             |
| ---------- | --------------------------------------- |
| `up`       | Service is healthy (default if omitted) |
| `down`     | Service has failed                      |
| `degraded` | Service is running but impaired         |

## Crontab Integration

```bash theme={null}
# Crontab entry with heartbeat
0 2 * * * /path/to/backup.sh && curl -fsS -H "X-API-Key: $KODO_API_KEY" https://kodostatus.com/api/heartbeat/MONITOR_ID
```

## Grace Periods

Allow some flexibility for job timing:

| Setting      | Description                       |
| ------------ | --------------------------------- |
| Interval     | How often heartbeats are expected |
| Grace period | Extra time before marking as late |

Example: 5-minute interval with 2x grace multiplier means alerts fire after 10 minutes of silence.

## Reporting Failures

Report when jobs fail:

```bash theme={null}
if /path/to/job.sh; then
  curl -X POST "https://kodostatus.com/api/heartbeat/MONITOR_ID" \
    -H "X-API-Key: $KODO_API_KEY" \
    -d '{"status": "up"}'
else
  curl -X POST "https://kodostatus.com/api/heartbeat/MONITOR_ID" \
    -H "X-API-Key: $KODO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"status": "down", "message": "Job failed with exit code 1"}'
fi
```

## Incident Safeguards

When a heartbeat is missed, the same [incident safeguards](/automation/incident-safeguards) apply as with uptime monitors:

* **Failure threshold** (default: 2 for heartbeats) -- must miss this many consecutive beats
* **Cooldown** -- prevents rapid duplicate incidents
* **Severity override** (default: Minor for heartbeats) -- configurable per monitor
* **Draft mode** and **notification batching** -- configured at the organization level
