GET /health
GET /health
Check whether the API is healthy. Always returns 200 OK, so read the status field for the result.
With the cache access token, the response also lists the status of each upstream token.
Headers (optional)
| Name | Required | Description |
|---|---|---|
Authorization | No | Cache access token for detailed status |
Example request (basic)
curl "https://api.betterlyrics.org/health"const res = await fetch("https://api.betterlyrics.org/health");
const data = await res.json();import requests
res = requests.get("https://api.betterlyrics.org/health")
data = res.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
res, err := http.Get("https://api.betterlyrics.org/health")
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
} Basic response
Status: 200 OK, Content-Type: application/json
{
"status": "ok",
"accounts": 2,
"accounts_active": 2,
"accounts_out_of_service": 0,
"circuit_breaker": "CLOSED",
"cache_ready": true
} Response fields
| Field | Type | Always present | Description |
|---|---|---|---|
status | string | Yes | One of ok, degraded, unhealthy. |
accounts | integer | Yes | Number of configured upstream accounts. |
accounts_active | integer | Yes | Accounts that are in service. |
accounts_out_of_service | integer | Yes | Accounts that are configured but out of service. |
circuit_breaker | string | Yes | One of CLOSED, OPEN, HALF-OPEN, UNINITIALIZED, UNKNOWN. |
circuit_breaker_retry_in | string | No | Go duration until the breaker retries. Present only when it is OPEN. |
cache_ready | boolean | Yes | Whether the cache is ready. |
error | string | No | Present when status is unhealthy. |
circuit_breaker_failures | integer | No | Admin token only. |
tokens | object[] | No | Admin token only. |
tokens[].name | string | Yes | shared_bearer_token for the shared token, or the account name. |
tokens[].type | string | Yes | bearer for the shared token, mut for an account token. One of bearer, mut. |
tokens[].status | string | Yes | See the token status values below. One of healthy, unhealthy, refreshing_soon, not_initialized, out_of_service, unknown. |
tokens[].expires | string | No | Expiry time as YYYY-MM-DD HH:MM:SS. bearer only, when initialized. |
tokens[].remaining_minutes | integer | No | Minutes until expiry. bearer only, when initialized. |
tokens[].last_checked | string | No | Time of the last health check (RFC 3339). mut only, after a check has run. |
tokens[].last_error | string | No | Error from the last health check. Only when status is unhealthy. |
tokens[].reason | string | No | Why the account is out of service. Only when status is out_of_service. |
tokens[].note | string | No | Only when status is unknown. |
Status values
| Status | Meaning |
|---|---|
ok | All systems operational |
degraded | The circuit breaker is OPEN. With the cache access token, also when an account token is unhealthy. |
unhealthy | No account is in service (none configured, or all out of service). See error. |
Token checks affect status only when the request has the cache access token, so an
authenticated request can report degraded while a basic request reports ok.
Authenticated response
With the Authorization header, the response includes more detail:
curl -H "Authorization: your-cache-token" \
"https://api.betterlyrics.org/health"const res = await fetch("https://api.betterlyrics.org/health", {
headers: { "Authorization": "your-cache-token" },
});
const data = await res.json();import requests
res = requests.get(
"https://api.betterlyrics.org/health",
headers={"Authorization": "your-cache-token"},
)
data = res.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://api.betterlyrics.org/health", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "your-cache-token")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
} {
"status": "ok",
"accounts": 2,
"accounts_active": 2,
"accounts_out_of_service": 0,
"circuit_breaker": "CLOSED",
"cache_ready": true,
"circuit_breaker_failures": 0,
"tokens": [
{
"name": "shared_bearer_token",
"type": "bearer",
"status": "healthy",
"expires": "2026-09-30 12:00:00",
"remaining_minutes": 10080
},
{
"name": "account-1",
"type": "mut",
"status": "healthy",
"last_checked": "2026-09-23T11:00:00Z"
},
{
"name": "account-2",
"type": "mut",
"status": "unknown",
"note": "health check not yet run"
}
]
} Token status values
| Status | Type | Meaning |
|---|---|---|
healthy | bearer, mut | Token is valid |
refreshing_soon | bearer | Token is valid and will be refreshed soon |
not_initialized | bearer | Token has not been fetched yet |
unhealthy | mut | The last health check failed. See last_error. |
out_of_service | mut | Account has no credentials and is not used |
unknown | mut | No health check has run yet |
Use cases
- Health checks in your own monitoring
- Checking that the API is reachable and working while you debug
- Showing API status on a status page or in your app