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

# Health checks and monitoring

> The API health endpoint reports the database, Redis, the last daily pipeline run, the failed job count and the open action count in one response.

Two endpoints answer two different questions. One says the web container is alive. The other says the whole pipeline is working.

## Endpoints

| URL                   | Answers                                     | Authentication |
| --------------------- | ------------------------------------------- | -------------- |
| `/api/health`         | Is the web container serving                | None           |
| `/api/backend/health` | Is the API alive, and is collection healthy | None           |

Both are reachable on the web origin, so an uptime check needs no credentials and no access to the API port.

## What does a healthy instance look like?

```json theme={null}
{
  "status": "ok",
  "db": "up",
  "redis": "up",
  "pipeline": {
    "lastDailyRunAt": "2026-07-30T03:00:12.000Z",
    "stale": false,
    "failedJobs": 0,
    "actions": {
      "generatedAt": "2026-07-30T04:11:02.000Z",
      "open": 7
    }
  }
}
```

| Field                     | Meaning                                                                            |
| ------------------------- | ---------------------------------------------------------------------------------- |
| `status`                  | `ok` when the database answers. The endpoint returns `503` when it does not        |
| `db`                      | `up` or `down`, from a real query rather than a connection count                   |
| `redis`                   | `up` or `down`. A Redis read that exceeds one second reports `down`                |
| `pipeline.lastDailyRunAt` | When the daily pipeline last started, or `null`                                    |
| `pipeline.stale`          | `true` when the last run is more than 26 hours old and at least one app is tracked |
| `pipeline.failedJobs`     | Failed jobs across the App Store, Google Play and alert queues                     |
| `pipeline.actions`        | When actions were last generated, and how many are open                            |

The 26 hour window is deliberate. A daily schedule plus a slow night should not page you, so `stale` only fires once a run has genuinely been missed. A fresh instance with no apps never reports stale, because there is nothing to collect.

## Monitor it

One command is enough for an uptime check.

```bash theme={null}
curl --fail --silent --show-error https://your-host/api/backend/health
```

`--fail` turns the `503` into a non zero exit status, which is what most monitoring agents key on.

To alert on a stalled pipeline rather than on a dead API, check the `stale` and `failedJobs` fields rather than the status code. A stale pipeline still answers `200`, because the API itself is healthy.

## Container health checks

Every Compose service defines its own health check, and the dependency order uses them: the API waits for PostgreSQL and Redis to report healthy, and the web app waits for the API.

```bash theme={null}
docker compose ps
```

`docker compose up --wait` blocks until every check passes, so a successful exit is a real signal rather than a process start.

## Related

<CardGroup cols={2}>
  <Card title="The daily pipeline and rate limits" icon="clock" href="/concepts/pipeline">
    What the pipeline does and when.
  </Card>

  <Card title="Troubleshooting" icon="life-buoy" href="/operations/troubleshooting">
    What to do when a field goes the wrong way.
  </Card>
</CardGroup>
