# Health, info, check and backup over HTTP > Check that the server is alive, read the tables, disk use and health of a database, look for damage, make and list backups, watch deferred trigger queues, and read the server's memory, processor and settings. - Category: HTTP API - Keywords: health, /health, monitoring, uptime, api/info, table list, recovery\_summary, damaged, last\_lsn, api/check, scrub, damage, api/backup, api/backups, api/restore, restore while running, point\_in\_time, api/databases/swap, swap databases, backup\_command, backup folder, --backups, last\_backup, server\_time\_ms, auth\_required, api/disk, disk usage, trash\_bytes, wal\_archive\_bytes, api/trigger-queue, trigger queue, deferred trigger, oldest\_pending\_age\_ms, zone\_partition\_skips, zone\_block\_skips, slice\_reads, slice\_cache\_hits, slice\_cache\_bytes, KARELADB\_SLICE\_CACHE\_MB, kdb\_slice\_reads\_total, cache\_pinned, cache\_verify\_checks, cache\_verify\_mismatches, rev\_values, wal\_archive\_mb, web\_dir, help\_dir, skill\_dir, metrics, /metrics, Prometheus, Grafana, slow queries, slow-query log, api/slow-queries, --slow-query-ms, KARELADB\_SLOW\_QUERY\_MS, trash\_purged\_bytes - See also: [HTTP API overview](http-overview.md), [Backup, check, repair and restore](backup-and-safety.md), [kareladb info, check, repair, dump-file](cli-maintenance.md), [Web console (health-box)](web-console.md#health-box), [Grafana and Prometheus](grafana.md) These routes tell you how the server and a database are doing. The [web console](web-console.md#health-box) uses them for its table list and health box. - `GET /health` is for monitoring: it needs no login and never touches data. - The other routes work on one database: `db=` or the header `X-KDB-Database` ([choosing the database](http-overview.md#database)). - Backups go to the backup folder: `_backups` in the data folder unless `--backups ` (or `KARELADB_BACKUP_DIR`, `backup_dir` in `kareladb.conf`) names another ([where the settings come from](backup-schedule.md#backup-settings)). ## GET /health Syntax: ```sql GET /health ``` Answers when the server is running. Use it to check that KarelaDB is up (a monitoring script, a load balancer, a start script that waits for the server). | Parameter | Where | Meaning | Default | |---|---|---|---| | (none) | - | No database, no login | - | | Answer field | Meaning | |---|---| | `status` | always `"ok"`: the server is running | | `ready` | `false` while the server still opens the default database after a start (a long log replay after a crash, a slow disk); `true` after that. Requests for that database wait until it is open; other databases answer at once | | `starting` | only while `ready` is `false`: what it is doing, like `opening the default database 'default': replaying the log, 12 s so far` | | `version` | the KarelaDB version | | `server_time_ms` | the server clock: milliseconds since 1970-01-01 UTC | | `auth_required` | `true` when other requests need a token or a login | | `login` | `true` when the data folder has users (the console then shows a login form instead of a token box) | - **Status codes:** 200; 503 while the server is stopping ([drain](cli-serve.md#stop)). When the server does not run, there is no answer at all (the connection is refused). - **Notes:** `/health` never needs a token or login, even on a server that has them. It does not open a database, so it stays fast when a database is busy. When every HTTP worker is busy with queries, `/health` does not wait in line behind them: a thread of its own answers it (plain HTTP; over https it waits for a worker as before). - **At start:** the port answers within about a second, however many databases the data folder holds. Only the default database is opened at start; every other one opens when it is first used. A start script that must wait for the default database waits for `"ready": true`. **HTTP: Is the server alive?** ```http GET /health ``` Response: HTTP 200 (application/json) ```text { "status": "ok", "version": "0.2.0-dev", "product": "KarelaDB", "server_time_ms": 1792662966061, "auth_required": false, "login": false, "tls": false, "ready": true, "standby": false } ``` ```bash curl -s http://127.0.0.1:9900/health ``` ```powershell # Wait until a server that is starting answers (at most 10 seconds). foreach ($i in 1..50) { try { $h = Invoke-RestMethod http://127.0.0.1:9900/health; "KarelaDB $($h.version) is up"; break } catch { Start-Sleep -Milliseconds 200 } } ``` ```python import requests try: h = requests.get("http://127.0.0.1:9900/health", timeout=3).json() print("up, version", h["version"]) except requests.RequestException: print("KarelaDB is down") ``` ## GET /api/info Syntax: ```sql GET /api/info[?db=] ``` Everything about one database: its tables and columns, sizes, damage, what happened when it was opened, and the last backup. | Parameter | Where | Meaning | Default | |---|---|---|---| | `db` | URL | The database (or the header `X-KDB-Database`) | the default database | | Answer field | Meaning | |---|---| | `database` | The database name | | `dir` | Its folder | | `version` | The KarelaDB version | | `opened_ms` | When the server opened the database (ms since 1970, UTC) | | `server_time_ms` | The server clock | | `last_lsn` | The number of the last change in the log (the **LSN**, log sequence number). It grows with every change. | | `data_files`, `data_bytes` | Count and size of the data files | | `tables[]` | One object per table: `name`, `kind` (`timeseries` or `relational`), `partition` (`NONE`, `DAY`, `MONTH`, `YEAR`), `timestamp_column`, `rows`, `bytes`, `columns[]`, `create_sql` | | `tables[].columns[]` | `name`, `type`, `primary_key`, `not_null`, `computed` (a column made from others), `references` (the table and column it points to, or empty) | | `damaged[]` | Damaged files KarelaDB knows about; empty when all is well | | `recovery_summary` | What KarelaDB did when it opened the database (for example after a crash) | | `warning` | A warning when the data is far bigger than `--memory`; `""` when all is well | | `backup_dir` | The backup folder of this database (empty when backups are off) | | `last_backup` | The newest backup (same fields as [POST /api/backup](http-server-info.md#post-api-backup)), or `null` | | `auth_required` | `true` when requests need a token or login | | `read_only` | `true` when this database only reads | | `protection` | The server's [protection](protection.md) settings: `statement_timeout_ms`, `max_result_bytes`, `max_groups`, `max_queries_per_user`, `safe_updates`, `running` (statements running now), `server_read_only`, `audit` | | `backup_schedule` | The [backup schedule](backup-schedule.md) and its last run, or `null` without a schedule | | `backup_command` | The [copy command](backup-schedule.md#backup-command) run after each backup and its last run, or `null` without one | | `timers` | How many [timers](timers.md) of this database are on | - **Status codes:** 200; 401/403 login or role (needs `read`); 404 unknown database; 500 the database cannot be read. - **Notes:** views, functions and procedures are not in `tables[]`; use `SHOW VIEWS`, `SHOW FUNCTIONS` and `SHOW PROCEDURES` with [/exec](http-exec.md#get-exec). **HTTP: A small database: one table** Setup: ```text CREATE TABLE brokers (id INT PRIMARY KEY, name STRING NOT NULL); INSERT INTO brokers VALUES (1, 'Keystone Securities'), (34, 'Vision Securities'); ``` ```http GET /api/info ``` Response: HTTP 200 (application/json) ```text { "database": "demo", "dir": "kdb-data/demo", "version": "0.2.0-dev", "product": "KarelaDB", "opened_ms": 1792662966072, "server_time_ms": 1792662966115, "last_lsn": 4, "data_files": 1, "data_bytes": 231, "tables": [ { "name": "brokers", "kind": "relational", "partition": "NONE", "timestamp_column": "", "rows": 2, "bytes": 0, "columns": [ { "name": "id", "type": "INT", "primary_key": true, "not_null": false, "computed": false, "references": "" }, { "name": "name", "type": "STRING", "primary_key": false, "not_null": true, "computed": false, "references": "" } ], "create_sql": "CREATE TABLE brokers (\n id INT PRIMARY KEY,\n name STRING NOT NULL\n)" } ], "damaged": [], "recovery_summary": "manifest copy: -, last shutdown: clean\nreplayed 0 transactions after LSN 0, last LSN 0\nopened in 1 ms: manifest 0 ms, 0 files read 0 ms, log check 0 ms, replay 0 ms (0 transactions), clean-up 1 ms", "warning": "", "backup_dir": "./backups/demo", "last_backup": null, "auth_required": false, "read_only": false, "protection": { "statement_timeout_ms": 60000, "max_result_bytes": 1073741824, "max_groups": 5000000, "max_queries_per_user": 32, "safe_updates": false, "running": 1, "server_read_only": false, "audit": true }, "backup_schedule": null, "backup_command": null, "timers": 0 } ``` ```powershell $info = Invoke-RestMethod "http://127.0.0.1:9900/api/info?db=market" "log LSN: $($info.last_lsn) damaged files: $($info.damaged.Count)" $info.tables | Select-Object name, kind, partition, timestamp_column, rows | Format-Table -AutoSize ``` ```js const info = await (await fetch("http://127.0.0.1:9900/api/info?db=market")).json(); for (const t of info.tables) console.log(t.name, t.kind, t.rows, t.columns.map((c) => `${c.name} ${c.type}`).join(", ")); ``` ## GET /api/disk Syntax: ```sql GET /api/disk[?db=] ``` What one database takes on disk, part by part. The console's [Keep data page](console-keep-data.md) shows it. It walks the trash folder, so it is a separate route and not part of `/api/info`. | Parameter | Where | Meaning | Default | |---|---|---|---| | `db` | URL | The database (or the header `X-KDB-Database`) | the default database | | Answer field | Meaning | |---|---| | `database` | The database name | | `data_files`, `data_bytes` | The current version of every file | | `tail_files`, `tail_bytes` | Of those: [tail files](partitions-and-dedup.md#tail-files), rows appended after a partition's file and not yet folded back into it | | `delta_files`, `delta_bytes` | Of those: [delta files](partitions-and-dedup.md#delta-files), rows of a partition replaced or deleted and not yet compacted into it | | `previous_files`, `previous_bytes` | Older versions kept for repairs (`PURGE VERSIONS` removes them) | | `trash_folders`, `trash_bytes` | Replaced files waiting in `_trash` to be removed (`PURGE TRASH`) | | `wal_bytes` | The log (the **WAL**) | | `wal_archive_bytes` | Old log kept for repairs and restores (`WAL_ARCHIVE`) | | `total_bytes` | All of the above together | | `trash_purged_bytes` | What the database removed from its trash by itself since it opened | - **Status codes:** 200; 401/403 login or role (needs `read`); 404 unknown database. - **Notes:** see [trash](trash.md) and [versions](versions.md) for how to free the space. **HTTP: Disk use of a small database** Setup: ```text CREATE TABLE brokers (id INT PRIMARY KEY, name STRING NOT NULL); INSERT INTO brokers VALUES (1, 'Keystone Securities'), (34, 'Vision Securities'); ``` ```http GET /api/disk ``` Response: HTTP 200 (application/json) ```text { "database": "demo", "data_files": 1, "data_bytes": 231, "tail_files": 0, "tail_bytes": 0, "delta_files": 0, "delta_bytes": 0, "previous_files": 0, "previous_bytes": 0, "trash_folders": 0, "trash_bytes": 0, "wal_bytes": 1048640, "wal_archive_bytes": 0, "total_bytes": 1048871, "trash_purged_bytes": 0 } ``` ## GET /api/trigger-queue Syntax: ```sql GET /api/trigger-queue[?db=][&trigger=][&wait=