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

VariableWhy
APP_KEYEncryption master key. Generate with php artisan key:generate. Never rotate without a re-encrypt migration.
APP_URLPublic URL, used to build widget snippets, OAuth callbacks, signed URLs.
DB_*Postgres connection.
REDIS_HOSTCache, sessions, queue, hot-path retrieval cache, conversation history cache.
QUEUE_CONNECTIONSet to redis in production.
SESSION_DRIVERredis in production.
CACHE_DRIVERredis.
WIDGET_JWT_SECRETHS256 signing secret for visitor JWTs. ≥ 32 random bytes.

LLM provider

At least one of the following:

VariableProvider
CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKENCloudflare Workers AI (preferred). Auto-binds Llama 3.3 70B + bge-base-en-v1.5.
OPENAI_API_KEYOpenAI direct.
OPENROUTER_API_KEYOpenRouter (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

VariableProvider
CLOUDFLARE_VECTORIZE_INDEXCloudflare Vectorize index name. Uses CLOUDFLARE_ACCOUNT_ID + token. Default pitchbar-chunks.
QDRANT_URL + QDRANT_API_KEYQdrant.

Set VECTOR_PROVIDER to force. Auto-binds based on available keys (Vectorize preferred).

Crawler

VariableStrategy
(uses CLOUDFLARE_*)Cloudflare Browser Rendering. Preferred.
BROWSERLESS_TOKEN + BROWSERLESS_URLBrowserless fallback.
(none)Plain HTTP. Free; no JS rendering.
VariablePurpose
CRAWL_MAX_PAGES_PER_SOURCEMax pages fan-out per Source. Default 500 (raised from 25 — buyers adding 100-URL sitemaps were silently losing 75 pages). Cap applies after sitemap-index recursion + dedupe.
CRAWL_PAGE_DISPATCH_DELAYPer-page delay (seconds) when fanning out sitemap pages so Cloudflare Browser Rendering's small per-account concurrency doesn't 429. Default 2.
CLOUDFLARE_BROWSER_RENDERINGSet to false to force the Browserless / plain-HTTP path even when Cloudflare keys are present. Default true.

RAG / retrieval

VariablePurpose
RAG_CONFIDENCE_THRESHOLDDefault similarity threshold for newly created agents. 0.5 for Cloudflare bge-base-en-v1.5 (its ANN cosine peaks lower than OpenAI's); 0.78 for OpenAI text-embedding-3-small. Auto-resolves based on LLM_PROVIDER.
RAG_RERANK_ENABLEDSet to false to disable the bge-reranker-base cross-encoder pass. Default true when Cloudflare keys are present.
VECTOR_DIMEmbedding dimension override. Leave unset to auto-resolve from the configured embed model via the known-model map (bge-base=768, bge-m3=1024, text-embedding-3-small=1536, etc.). Set explicitly only when pointing at an unlisted model. Changing this on an existing install needs php artisan vector:rebuild-index — the Vectorize index is provisioned at the dim active when it was first created and cannot be resized in place.

Cloudflare AI Gateway (optional)

VariablePurpose
CLOUDFLARE_AI_GATEWAY_URLIf set, Workers AI calls route through Cloudflare's AI Gateway — observability, caching, rate limits.
CLOUDFLARE_CHAT_MODELDefault @cf/meta/llama-3.3-70b-instruct-fp8-fast.
CLOUDFLARE_EMBED_MODELDefault @cf/baai/bge-base-en-v1.5.
CLOUDFLARE_VECTORIZE_INDEXVectorize index name. Default pitchbar-chunks.
OPENROUTER_CHAT_MODELOpenRouter chat model slug. Default meta-llama/llama-3.3-70b-instruct:free.
OPENROUTER_EMBED_MODELOpenRouter embedding model. Default text-embedding-3-small.
QDRANT_COLLECTIONQdrant collection name when using the Qdrant vector store fallback. Default pitchbar_chunks.

S3 / R2 (object storage for file uploads)

VariablePurpose
AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEYBucket credentials. For Cloudflare R2, use the R2 token's key/secret pair.
AWS_DEFAULT_REGIONRegion of the bucket. Use auto for R2.
AWS_BUCKETBucket name.
AWS_ENDPOINTCustom S3-compatible endpoint. Required for R2 (e.g. https://<accountid>.r2.cloudflarestorage.com). Leave blank for native AWS S3.
AWS_USE_PATH_STYLE_ENDPOINTtrue for R2 and most non-AWS S3 implementations; false for native AWS.

Frontend (Vite)

VariablePurpose
VITE_WIDGET_CDN_URLBase URL the visitor widget loader uses. Defaults to http://localhost:5173 in dev. In production, point at the public origin serving /widget/widget.js.

Stripe

VariablePurpose
STRIPE_KEYPublishable key.
STRIPE_SECRETSecret key. Used for plan sync and Cashier.
STRIPE_WEBHOOK_SECRETSigning secret for incoming webhooks (whsec_…).
CASHIER_CURRENCYDefaults to usd.

Reverb (realtime)

VariablePurpose
REVERB_APP_KEYPublic app key. Embedded in widget init payload.
REVERB_APP_SECRETSecret. Server-side only.
REVERB_APP_IDApp identifier.
REVERB_HOSTPublic hostname for the Reverb server.
REVERB_PORTDefault 8080.
REVERB_SCHEMEwss in production, ws locally.

Mail

VariablePurpose
MAIL_MAILERsmtp / postmark / resend / etc.
MAIL_FROM_ADDRESSSender address. Required.
MAIL_FROM_NAMEDisplay name.
MAIL_HOST / MAIL_PORT / MAIL_USERNAME / MAIL_PASSWORDSMTP credentials.

Branding

VariablePurpose
BRANDING_LABELDefault "Powered by Pitchbar" label. Override in app_settings for white-label.
BRANDING_URLWhere the label links to.
BRANDING_FOOTER_LOGO_PATHStorage path to the footer logo image.

Observability

VariablePurpose
SENTRY_LARAVEL_DSNError reporting. (Some hosts still ship the legacy SENTRY_DSN name; the Laravel SDK reads SENTRY_LARAVEL_DSN as of v4.x — keep both in .env for back-compat if you migrated.)
OTEL_EXPORTER_OTLP_ENDPOINTOpenTelemetry collector. Honeycomb / Grafana Cloud.
OTEL_SERVICE_NAMEService name in traces. Default pitchbar.

Payment gateways

VariablePurpose
PAYPAL_ENABLEDSet to true to expose PayPal at checkout.
PAYPAL_MODEsandbox or live.
PAYPAL_CLIENT_ID + PAYPAL_CLIENT_SECRETREST API credentials.
PAYPAL_WEBHOOK_IDFor verify-signature webhook checks.
RAZORPAY_ENABLEDSet to true to expose Razorpay at checkout.
RAZORPAY_API_KEY + RAZORPAY_SECRET_KEYHTTP Basic auth keys.
RAZORPAY_WEBHOOK_SECRETHMAC-SHA256 signing secret for webhook bodies.

OAuth integrations

VariablePurpose
NOTION_CLIENT_ID + NOTION_CLIENT_SECRET + NOTION_REDIRECT_URINotion public-integration credentials for connecting Notion pages as knowledge sources.
GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET + GOOGLE_REDIRECT_URIGoogle OAuth (Drive + Docs + Sheets) — register an OAuth client in the GCP console with drive.readonly, documents.readonly, and spreadsheets.readonly scopes. Omitting spreadsheets.readonly blocks the Google Sheets source type.

Marketing demo widget

VariablePurpose
MARKETING_DEMO_AGENT_IDUUID of a published agent that powers the live demo widget on the marketing pages. Add the marketing site URL to that agent's allowed_origins.
DEMOSet to true to open Login / Get started links in a new tab on the marketing site — useful for reviewers exploring a CodeCanyon live demo without losing the marketing page when they hop into the app.

Queue tick (Cloudflare Worker cron)

VariablePurpose
INTERNAL_QUEUE_TOKENShared bearer secret protecting POST /api/v1/internal/queue-tick. The Cloudflare Worker cron pings this every 60s to drive the queue when in-cluster scheduling isn't available.

App Settings overrides

The app_settings singleton row stores plaintext-encrypted overrides for:

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.