---
title: "Can the writing pipeline actually run right now?"
method: GET
path: "/generation-health"
tags: ["Credits"]
---

# Can the writing pipeline actually run right now?

`GET /generation-health`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/generation-health`
- Auth: HTTP bearer

Reports, per critical sidecar, the resolved provider fallback chain and whether ANY link in it is currently reachable. A chain whose every link is cooling down is the shape that parks jobs indefinitely — the job defers for provider recovery to a retry that cannot succeed — and it is otherwise only visible as a misleading generation timeout. Check this before blaming a failed job on your request, and when triaging repeated failures. A link whose stored API key this server cannot decrypt is never healthy, and a request that reaches it fails there with no fallback tried, so its sidecar is unreachable even with a healthy fallback; its `unreachableReason` and the entry's `reason` name the fix (re-enter the key, or fix the server's AI_ENCRYPTION_KEY). Reports posture only; never provider credentials or base URLs.

## Query parameters

- `probe` boolean

## Response `200`

Generation health summary.

- GenerationHealthEnvelope
  - `health` object, required
    - `healthy` boolean, required: True only when every critical sidecar can reach a healthy provider. Without ?probe this is derived from provider flags and recorded cooldowns, so a provider that has not been TRIED since it died still counts as healthy — its failure streak is zero precisely because nothing has failed against it yet. With ?probe=true it is replaced by what the providers actually answered.
    - `checkedAt` string, date-time, required
    - `sidecars` GenerationHealthEntry[], required
      - `sidecar` string, required
      - `healthy` boolean, required: False when this sidecar can reach no healthy provider — including when it is bound to none at all. Also false when a request would reach a link whose stored API key this server cannot decrypt, even with a healthy fallback behind it: the request fails at that link and no fallback is tried, so the sidecar is unreachable until the key is fixed. (A link cooling down is routed past before its key is read.)
      - `reason` string, nullable, required: Null when the bound provider itself is healthy. Otherwise one line: the link every request fails at and why (an unreadable API key names its fix: re-enter the key, or fix the server's AI_ENCRYPTION_KEY), each link that cannot serve and why, or, when a fallback serves, the bound provider's problem and the fallback that serves instead.
      - `chain` ProviderChainLink[], required: The resolved fallback chain, in order.
        - `label` string, required
        - `modelId` string, required
        - `healthy` boolean, required: Active, its stored API key readable by this server, and not currently cooling down. A key that cannot be decrypted fails every request at this link, so the link is never healthy.
        - `cooldownUntil` string, date-time, nullable, required
        - `failureStreak` integer, required
        - `unreachableReason` string, nullable, required: Why this link cannot serve a request, or null when it can: the provider row is inactive; it is an image, video or music model, which cannot answer a text call; its API key cannot be read (names the fix: re-enter the key, or fix the server's AI_ENCRYPTION_KEY when no stored key can be read); or it is cooling down until a stated time.
      - `cyclic` boolean, required: True when the chain loops back on itself; a configuration error worth fixing before it parks jobs.
    - `misboundSidecars` object[], required: Every active text sidecar, critical or not, bound to an image, video or music provider. Such a sidecar cannot generate at all: its text call fails before reaching the provider. A critical one also reads unhealthy in `sidecars`; any other is reported only here. Empty when every text sidecar is on a text model.
      - `sidecar` string, required
      - `feature` string, required
      - `provider` string, required: The bound provider row's label.
      - `providerType` string, required
      - `modelId` string, required
      - `reason` string, required: What is wrong and the fix: bind a text model.
  - `bindingProbes` object[]: Present only when ?probe=true. Per critical sidecar, a real (small) call against EVERY link of its fallback chain, in order, stopping at the first link that answers. Probing only the bound provider answered a different question from the one this endpoint asks: the link that decides whether a request can be served is usually not the first one. When probes run they also override `health.healthy`, because an answer from the provider outranks a recorded flag.
    - `sidecar` string, required
    - `usable` boolean, required: True when SOME link in the chain answered — the honest form of "can this sidecar generate right now".
    - `servedBy` string, nullable, required: Label of the link that actually answered, or null when none did. When this is NOT the primary, the pipeline is running on a different model than the one bound — a quality variable, not a no-op.
    - `links` object[], required: Each link probed, in chain order, ending at the one that answered. A chain that serves requests from its third link shows all three.
      - `label` string, required
      - `modelId` string, required
      - `verdict` object, required: usable:true, or usable:false with reason `unreachable` (could not be called at all), `rejects_call_shape` (refuses the sampling parameters we send — bind a param-shim variant), `unusable_output` (answers, but with nothing the pipeline can use), or `api_key_undecryptable` (its stored API key cannot be decrypted by this server, so it was not called; `detail` names the fix: re-enter the key, or fix the server's AI_ENCRYPTION_KEY).
    - `guidance` string, required: One line on what to do: usable, served by a named fallback, or nothing in the chain can serve a request.

## Other responses

- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/4534f5d25540?raw)
