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

# Health

# Health

Two health endpoints ship in v1: an unauthenticated **liveness probe**
and an authenticated **canary probe**. Both return a small JSON body
suitable for direct consumption by uptime checkers and your own
deployment smoke tests.

***

## `GET /v1/health` — public liveness probe

Unauthenticated. No `Authorization` header is required (and any header
you send is ignored).

```bash theme={null}
curl -i https://api.scripe.io/v1/health
```

### Response (healthy)

```http theme={null}
HTTP/1.1 200 OK
Cache-Control: max-age=5, public
Content-Type: application/json

{
  "status": "ok",
  "version": "2026-08-01",
  "checks": {
    "db": { "ok": true, "latencyMs": 9 },
    "redis": { "ok": true, "latencyMs": 3 },
    "auditBuffer": { "ok": true, "depth": 14 }
  }
}
```

### Response (degraded)

```http theme={null}
HTTP/1.1 503 Service Unavailable
Content-Type: application/json

{
  "status": "degraded",
  "version": "2026-08-01",
  "checks": {
    "db": { "ok": true, "latencyMs": 12 },
    "redis": { "ok": false, "latencyMs": 0, "error": "ECONNREFUSED" },
    "auditBuffer": { "ok": false, "depth": null, "error": "redis_unavailable" }
  }
}
```

### Semantics

| Field                      | Meaning                                                               |
| -------------------------- | --------------------------------------------------------------------- |
| `status`                   | `"ok"` or `"degraded"`. **Switch on this** rather than HTTP status.   |
| `version`                  | The API version this instance currently advertises as default.        |
| `checks.db.ok`             | DB connectivity. `false` is a hard outage; the read API will fail.    |
| `checks.redis.ok`          | Redis connectivity. `false` degrades rate limiting + audit buffering. |
| `checks.auditBuffer.ok`    | Whether the audit-write queue can accept rows.                        |
| `checks.auditBuffer.depth` | Combined LLEN across all 16 shards. Useful for SRE dashboards.        |

We return **HTTP 503** when `status === "degraded"` so naive uptime
checkers correctly mark the service unhealthy.

The response is cached at the edge for 5 seconds (`Cache-Control:
max-age=5, public`). Don't rely on this probe for sub-second observability;
use the Sentry / Datadog spans for that.

### When to use

* **Container readiness probes.** Kubernetes / Vercel-style checks.
* **External uptime monitors.** Pingdom, BetterUptime, etc.
* **Pre-deploy smoke tests.** Block a deploy if the canary returns 503.

### When NOT to use

* **Per-request latency tracking.** Cached for 5 s; the latency you see
  is bounded by the cache, not by the API.
* **Authenticated canary checks.** Use `/v1/health/auth` instead — that
  one exercises the auth path too.

***

## `GET /v1/health/auth` — authenticated canary

Same shape, but the request must carry a valid `Authorization` header.
Use this after a deploy to confirm both the unauth surface AND the API
key path are healthy from your client's perspective.

```bash theme={null}
curl -i https://api.scripe.io/v1/health/auth \
  -H "Authorization: Bearer scripe_sk_live_…" \
  -H "Scripe-Api-Version: 2026-08-01"
```

### Response

```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "ok",
  "version": "2026-08-01",
  "principal": {
    "type": "api_key",
    "id": "key_01J9ZAB…",
    "scopes": ["notes:read", "posts:read"]
  },
  "workspace": { "id": "org_2pYJfL3…" }
}
```

The body is intentionally minimal — it's a canary, not an introspection
endpoint. For the full workspace + plan + features payload, call
[`/v1/workspaces/me`](./workspaces.md).

A `503` here means the same downstream subsystems used by the public
probe are unhealthy. A `401` here means the key is bad — investigate
that before you investigate the API.

### Counted against the rate limit?

Yes — `/v1/health/auth` consumes from the workspace's `read` bucket so a
broken canary loop can't bypass quota. The unauthenticated `/v1/health`
does **not** count, and is rate-limited only at the IP layer.

***

## Errors

| Status | Code                                                             | When                                      |
| ------ | ---------------------------------------------------------------- | ----------------------------------------- |
| 200    | (none)                                                           | All checks healthy.                       |
| 401    | `unauthenticated`, `invalid_token`, `key_revoked`, `key_expired` | Auth probe only.                          |
| 429    | `rate_limited`                                                   | Auth probe only — workspace quota burned. |
| 503    | `service_unavailable`                                            | At least one downstream check failed.     |

See [errors/](./errors/) for the full catalogue.
