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

# Environment Variables Reference

> The complete, accurate set of environment variables Fit4Life OS reads, required secrets, optional toggles, and the variables that flip Clover and Uber from stub to live.

All secrets are read **server-side only**, through `src/lib/server/env.ts` and the adapter selectors. Values live in `.env.local` (gitignored) for local dev and in Vercel's encrypted env for deploys. This page is the authoritative list, it reflects what the code actually reads.

## Required

The app throws on startup if these are missing (or, for the DB, when a `/live` query runs).

| Variable              | Used by         | Purpose                                                 |
| --------------------- | --------------- | ------------------------------------------------------- |
| `TWILIO_ACCOUNT_SID`  | `env.ts`        | Twilio auth                                             |
| `TWILIO_AUTH_TOKEN`   | `env.ts`        | Twilio auth + webhook signature verify                  |
| `TWILIO_PHONE_NUMBER` | `env.ts`        | The bot's `from` number                                 |
| `ANTHROPIC_API_KEY`   | bot + assistant | Claude API (separate from the Claude Code subscription) |
| `DATABASE_URL`        | `db.ts`         | Neon Postgres connection (the `/live` source of truth)  |

<Note>
  `botConfigured()` returns true only when the three `TWILIO_*` vars **and** `ANTHROPIC_API_KEY` are all present. Outbound SMS (clinic/owner notify, ops reply) is gated on this.
</Note>

## Optional toggles

| Variable                                | Effect when set                                                                                                                                                                                                                                                                                                         |   |                       |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | --------------------- |
| `TWILIO_MESSAGING_SERVICE_SID`          | Outbound SMS routes **through** the A2P Messaging Service instead of the bare `from`. Required for reliable A2P 10DLC delivery.                                                                                                                                                                                         |   |                       |
| `TWILIO_WEBHOOK_URL`                    | Signature verification uses this exact URL verbatim (avoids `x-forwarded-host` trust + dropped query strings).                                                                                                                                                                                                          |   |                       |
| `CLINIC_NOTIFY_NUMBER`                  | Where "order is PAID, ready to fulfill" alerts go.                                                                                                                                                                                                                                                                      |   |                       |
| `OWNER_NOTIFY_NUMBER`                   | Fallback notify target (\`clinicNotifyNumber                                                                                                                                                                                                                                                                            |   | ownerNotifyNumber\`). |
| `OS_PASSWORD`                           | The shared password that gates `/live` + `/ops` at `/login`.                                                                                                                                                                                                                                                            |   |                       |
| `OPS_SECRET`                            | The ops-API `Authorization: Bearer` credential (transmitted, compared only).                                                                                                                                                                                                                                            |   |                       |
| `SIGNING_SECRET`                        | HMAC key for session cookies, export share links, and pay-link tokens. Kept separate from `OPS_SECRET` so a leaked Bearer value cannot forge signed tokens offline. Falls back to `OPS_SECRET` when unset (pre-split environments); set it everywhere real. Rotating it invalidates all sessions and outstanding links. |   |                       |
| `KV_REST_API_URL` / `KV_REST_API_TOKEN` | Upstash Redis (conversation store + automation flags). Without them the store falls back to an in-memory `Map`.                                                                                                                                                                                                         |   |                       |

## Adapter flips (stub → live)

These are read **only** in `src/lib/server/adapters/index.ts`. No call site branches on them, so setting them switches stub → real with zero code change. **Redeploy after adding them**: env changes do not apply to an existing deployment.

| Provider            | Goes live when these are present                                                              |
| ------------------- | --------------------------------------------------------------------------------------------- |
| **Clover** payments | `CLOVER_ECOMM_PUBLIC_TOKEN` **and** `CLOVER_ECOMM_PRIVATE_TOKEN` **and** `CLOVER_MERCHANT_ID` |
| **Uber** delivery   | `UBER_API_KEY`                                                                                |

With Clover live, "sending an invoice" mints a signed, expiring link to the branded public `/pay/[token]` page. The PUBLIC token renders Clover's hosted card iframe in the customer's browser (card data never touches the app); the PRIVATE token charges server-side via the Clover Ecommerce API. The charge response is synchronous: a succeeded charge commits the order and notifies the clinic inline, no webhook involved.

Related optional variables, read by the adapters, pay flow, and webhooks (not by the selector):

| Variable                | Purpose                                                                                                                                                              |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CLOVER_ENV`            | `sandbox` (default) or `production`, selects the Clover API + card-iframe SDK hosts.                                                                                 |
| `APP_BASE_URL`          | Public origin used in texted pay links. Falls back to `VERCEL_URL`, then `http://localhost:3000`. Set it to the branded domain in production.                        |
| `CLOVER_WEBHOOK_SECRET` | Only for the optional `/api/clover/webhook` endpoint, which the pay flow does not use. That webhook fails closed: without this secret, every POST to it is rejected. |
| `UBER_WEBHOOK_SECRET`   | Required for `/api/uber/webhook` to accept delivery-status events. Same fail-closed rule: without this secret, every POST to it is rejected.                         |

All three inbound webhooks (Twilio SMS, Clover, Uber) also reject replays: a correctly signed request is processed exactly once (tracked in the shared Redis store), so a captured request cannot be re-sent to repeat its effect.

<Warning>
  Do not trust env-var names from memory or auto-generated docs. The Clover/Uber names above are exactly what `cloverConfigured()` and `uberConfigured()` check, there is no `CLOVER_API_KEY`, `UBER_CLIENT_ID`, or `UBER_CUSTOMER_ID` in the selector.
</Warning>

## Neon-managed variables

The Neon Vercel integration manages `DATABASE_URL`, `POSTGRES_URL`, `DATABASE_URL_UNPOOLED`, `PGPASSWORD`, etc., they share one credential. In Vercel they are rotated via **Settings → Environments → Production → ⋯ → Rotate Integration Secrets** (not a manual edit), then a redeploy. See [Deployment](/docs/architecture/deployment).
