Check that the API is up
Two probes that take no key say whether the API serves and whether its dependencies answer, and one operation says what happens while the ledger is unreachable.
The three operations of this page say how the API itself is doing. Two of them are probes: they stand outside /v1, take no API key and answer with a plain object that is not wrapped in data. The third is an ordinary operation of /v1 and takes a key.
Which probe to call
| Probe | What it answers |
|---|---|
GET /health | 200 as soon as the API can serve a request. The state of MySQL and of Redis is in the body: ok, or down followed by the reason. |
GET /ready | 200 when MySQL and Redis both answer, and 503 when one of them does not. The body of a 503 names that dependency in failed. |
Call /ready where the status of the answer decides something, as in a load balancer or an uptime monitor. Call /health to read which release is running and what is down: its status stays 200 while a dependency is down.
When the ledger is unreachable
Slen writes every hold and every capture to its ledger. GET /v1/degraded-status says what the API does while the ledger does not answer, and what that left behind in the project of the key.
modeis a setting of the service, the same for every project:fail_closedorfail_open_with_cap. While the ledger is unreachable, a request that would spend is refused in either mode:503with the codeledger_unavailable.degraded_nowistruefrom the first call that was let through until the last of them is priced. The webhook eventsledger.degradedandledger.restoredmark the start and the end of that period.journal_depthcounts the calls that still wait to be priced.failed_depthcounts the calls that could not be priced. Their cost is not in the ledger.
The healthy answer is degraded_now set to false with a journal_depth of zero.
Operations
Liveness, with the state of each dependency in the body
GET /health
- No API key needed
- Available in the SDK for PHP and Node.js
Answers 200 as soon as PHP can serve; a dependency that is down is named in the body, not in the status. For a strict check use GET /ready. Not authenticated.
Responses
The process serves
Headers
X-Request-Id
{
"app": "string",
"release": "string",
"server": "string",
"mysql": "string",
"redis": "string",
"queue": "string",
"broadcast": "string",
"opcache_preloaded_files": 1,
"opcache_cached_scripts": 1
}Readiness — whether MySQL and Redis answer
GET /ready
- No API key needed
503 while a dependency is unreachable, so an orchestrator stops routing traffic to the instance. Not authenticated.
Responses
Every dependency answers
Headers
X-Request-Id
{
"status": "ok",
"failed": {
"key": "string"
}
}Errors
| Status | Codes | When |
|---|---|---|
| 503 | A dependency is unreachable; |
Headers
X-Request-Id
The body of every error is the error envelope.
Is the ledger answering, and what did fail-open let through while it was not
GET /v1/degraded-status
- Scope:
read
The degraded mode as it stands for the caller's project — an API key's own, a person's active one. Everything here is read from Redis, and the route skips the database pre-check, so the page answers while MySQL does not: it is the page somebody opens because the database is unreachable.
mode— what the installation does when the ledger stops answering:fail_closed(the default) refuses with503 ledger_unavailable;fail_open_with_capserves a direct gateway call without a hold, up to a per-minute cap per project, and writes each one down to be priced later. One setting for the installation, not per project. No route makes a direct gateway call any more, and a flow execution is never served degraded, so an outage of the ledger is refused under either mode.degraded_now— the project is inside a degraded window: a call was served without the ledger. The window closes when reconciliation has priced the last such call, not when the database answers again.journal_depth,failed_depth— the calls still waiting to be priced, and the ones reconciliation gave up on (they need a person).last_transition_at— when the project last entered or left the window;nullif it never did, or when Redis cannot be read (thendegraded_nowreadsfalseas well).
Responses
The degraded-mode state of this project's plane
{
"data": {
"mode": "fail_closed",
"degraded_now": true,
"journal_depth": 1,
"failed_depth": 1,
"last_transition_at": "2026-10-02T09:30:00Z"
}
}Examples
Read the state of the API
The probe needs no key. release names the release that answered.
curl https://api.slen.ai/api/health{
"app": "Slen",
"release": "1.0.8",
"server": "octane/frankenphp",
"mysql": "ok",
"redis": "ok",
"queue": "rabbitmq",
"broadcast": "reverb",
"opcache_preloaded_files": 1482,
"opcache_cached_scripts": 2913
}Ask whether the API is ready
The status of the answer is the answer: 200 here, 503 while a dependency is unreachable.
curl https://api.slen.ai/api/ready{
"status": "ok"
}Read the state of the ledger
This answer is the healthy one: no call was let through without a hold, and none waits to be priced.
curl https://api.slen.ai/api/v1/degraded-status \
-H "Authorization: Bearer $SLEN_API_KEY"{
"data": {
"mode": "fail_closed",
"degraded_now": false,
"journal_depth": 0,
"failed_depth": 0,
"last_transition_at": null
}
}Where to go next
Overview — the
datawrapper the two probes do not use.Authentication — the key
GET /v1/degraded-statustakes.Error codes — every code of the API, what it means and what to do about it.
Webhooks — how
ledger.degradedandledger.restoredarrive.
Built from openapi b070e1f, sdk contract 6a2e0e0, php 4089db3, node 0fa87be