Pitchbar reads its configuration from the standard Laravel
.env, with overrides for some keys available via the
platform admin's App Settings page so you can swap
Stripe / mail / LLM credentials without redeploying.
Required
Variable
Why
APP_KEY
Encryption master key. Generate with php artisan key:generate. Never rotate without a re-encrypt migration.
APP_URL
Public URL, used to build widget snippets, OAuth callbacks, signed URLs.
DB_*
Postgres connection.
REDIS_HOST
Cache, sessions, queue, hot-path retrieval cache, conversation history cache.
QUEUE_CONNECTION
Set to redis in production.
SESSION_DRIVER
redis in production.
CACHE_DRIVER
redis.
WIDGET_JWT_SECRET
HS256 signing secret for visitor JWTs. ≥ 32 random bytes.
LLM provider
At least one of the following:
Variable
Provider
CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN
Cloudflare Workers AI (preferred). Auto-binds Llama 3.3 70B + bge-base-en-v1.5.
OPENAI_API_KEY
OpenAI direct.
OPENROUTER_API_KEY
OpenRouter (router across many providers).
Set LLM_PROVIDER to force a binding (cloudflare,
openai, openrouter). When unset, the resolver
picks based on which keys are available, in the priority above.
Vector store
Variable
Provider
VECTORIZE_INDEX
Cloudflare Vectorize index name. Uses CLOUDFLARE_ACCOUNT_ID + token.
QDRANT_URL + QDRANT_API_KEY
Qdrant.
Set VECTOR_PROVIDER to force. Auto-binds based on
available keys (Vectorize preferred).
The app_settings singleton row stores plaintext-encrypted
overrides for:
Stripe secret + webhook secret + publishable key.
Mail driver settings.
Cloudflare / OpenAI / OpenRouter keys.
Branding (label, URL, logo).
The AppSettingsOverrideServiceProvider reads this on boot
and merges into config(). Setting things via the admin
panel is preferred for production — you don't have to re-deploy when a
key rotates.
APP_KEY rotation requires a manual migration. The
encrypted columns in app_settings were sealed with the
old key; rotating without re-encrypting renders them unreadable.