Jose Madrid Salsa uses environment variables for all secrets, API keys, and runtime configuration. Variables prefixed with NEXT_PUBLIC_ are exposed to the browser; all others are server-only.
Never commit .env files to version control. Use .env.example as a reference template and configure real values in Vercel or your local .env.local file.
64-character hex string (32 bytes) for AES-256-GCM encryption of service keys. Generate with node -e "console.log(require('crypto').randomBytes(32).toString('hex'))".
ENCRYPTION_KEY
Yes
Base64-encoded key for SMTP password encryption. Generate with node -e "console.log(require('crypto').randomBytes(64).toString('base64'))".
Bearer token Vercel Cron sends to /api/cron/*. Outside production a missing value is allowed; in production a missing value makes every cron route refuse, rather than leaving them world-callable. See Scheduled Jobs.
Default sender address. Defaults to orders@josemadridsalsa.com.
BUSINESS_POSTAL_ADDRESS
No
Physical mailing address printed in marketing-email footers, as CAN-SPAM requires. Defaults to the Zanesville address.
FUNDRAISING_REPLY_TO
No
Reply-to address on fundraiser re-signup invitations. Defaults to the owner's address.
EMAIL_IMAGE_BASE_URL
No
Absolute base URL for email header and footer images. Email clients cannot resolve relative paths, so every image needs a full URL. Defaults to https://www.josemadrid.net/email-templates; point it at the Vercel Blob store to serve the assets from there instead. No trailing slash.
Read/write token for the josemadridsalsa-blob Vercel Blob store. Powers the Developer Console file explorer (/admin/developer/files), the product image uploader, and the images:sync / images:migrate scripts. Get it from Vercel → Storage → josemadridsalsa-blob. Without it, every blob upload path is disabled and returns 503.
The Client ID and Secret are optional here — the preferred place to enter them is
Admin → Settings → Integrations, which stores the secret encrypted in the database. These
variables exist as a fallback and are read only when no admin-entered credentials are present.
QUICKBOOKS_ENVIRONMENT has no admin-panel equivalent and must be set to reach real company
data: it defaults to sandbox, and the Connect button on the integrations page connects to
whichever environment it names. Left unset in production, the flow completes successfully against
an Intuit sandbox company and syncs nothing real.
Variable
Required
Description
QUICKBOOKS_ENVIRONMENT
To reach live books
sandbox (default) or production. Selects both the Intuit API host and which stored credential set is used.
The redirect URI is derived from NEXTAUTH_URL as {NEXTAUTH_URL}/api/integrations/quickbooks/callback
and must be registered verbatim in the Intuit app. Sandbox and production keys are different pairs,
and credentials are stored per environment — production keys saved while the app is in sandbox mode
are filed under sandbox and will not work.
Legacy aliases for the SHIPPING_ORIGIN_* variables above, still read as a fallback. Prefer SHIPPING_ORIGIN_*
Set the warehouse address
Rate quoting and label purchase both read the warehouse address through
lib/shipping/origin.ts, which takes Settings → Shipping first and these variables second.
Until one of the two is complete, no real carrier rate can be fetched — checkout falls back to
flat-rate estimates and logs why.
They used to be configured separately: quoting read SHIPPING_ORIGIN_* and defaulted to a
placeholder address in San Francisco when unset, while label purchase read SHIP_FROM_*. A
half-configured deployment therefore quoted customers from one address and shipped from another,
with nothing in the response to indicate it.
Set these in apps/agent/.env.local, not the storefront's.
Variable
Required
Description
AI_GATEWAY_API_KEY
One of these
Vercel AI Gateway key used to reach the agent's model
VERCEL_OIDC_TOKEN
One of these
Pulled automatically by eve link; the alternative to an AI Gateway key
STOREFRONT_API_URL
No
Base URL the agent's read-only tools call. Defaults to https://www.josemadrid.net. Point it at http://localhost:3000 to run against a local storefront.