Environment Variables

Source: .env.example + extra vars referenced in code.

Required

Name Used by Purpose
DATABASE_URL src/lib/db/index.ts Neon Postgres connection string
NEXTAUTH_SECRET middleware.ts, src/lib/auth/options.ts JWT signing secret
NEXTAUTH_URL src/lib/auth/options.ts, billing checkout Public site URL (e.g. http://localhost:3000)
AWS_ACCESS_KEY_ID src/lib/providers/* AWS credentials for SES + SNS
AWS_SECRET_ACCESS_KEY src/lib/providers/* AWS credentials
AWS_REGION src/lib/providers/* AWS region (default us-east-1)
STRIPE_SECRET_KEY src/lib/billing/stripe.ts Stripe API key
STRIPE_WEBHOOK_SECRET src/app/api/webhooks/stripe/route.ts Stripe webhook signing secret

Optional (conditionally required)

Name Used by Purpose
STRIPE_PRO_PRICE_ID src/app/api/internal/billing/route.ts Stripe Price ID for Pro plan checkout
STRIPE_EMAIL_OVERAGE_METER_EVENT src/app/api/cron/report-overage/route.ts Stripe meter event name for email overage. Required for monthly overage billing.
STRIPE_SMS_OVERAGE_METER_EVENT same Stripe meter event name for SMS overage
UPSTASH_REDIS_REST_URL src/lib/api/rate-limit.ts Redis REST URL. If missing, rate limiting is skipped.
UPSTASH_REDIS_REST_TOKEN src/lib/api/rate-limit.ts Redis REST token
SYSTEM_FROM_EMAIL email-verification, password-reset, team-invite SES-verified From: for system emails. Fallback: no-reply@sendoka.com.
CRON_SECRET src/app/api/cron/* Bearer secret Vercel Cron uses to call cron endpoints. If unset, cron routes are open (dev only).
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET src/lib/auth/options.ts Enables Google OAuth login when both are set
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET src/lib/auth/options.ts Enables GitHub OAuth login when both are set
UNSUBSCRIBE_SECRET src/lib/api/unsubscribe.ts HMAC key for signing one-click unsubscribe tokens. Falls back to NEXTAUTH_SECRET. Required in production.
UNSUBSCRIBE_TOKEN_MAX_AGE_DAYS src/lib/api/unsubscribe.ts Max age of a verified unsubscribe token, in days. Default 365. Tokens without an iat claim (legacy) are accepted indefinitely.
TRACKING_SECRET src/lib/api/tracking.ts HMAC key for open/click tracking URL signatures. Falls back to NEXTAUTH_SECRET.
ALLOW_IDEMPOTENCY_WITHOUT_REDIS src/lib/api/idempotency.ts When Upstash is unset, set to 1 to allow idempotency to degrade to DB-only. Otherwise the idempotency middleware fails closed.
IDEMPOTENCY_TTL_HOURS src/lib/api/idempotency.ts Stored idempotency response cache TTL in hours. Default 24. Range 1–168; values outside fall back to default.
ARCHIVE_AUDIT_LOGS src/app/api/cron/retention/route.ts When true, the nightly retention cron uploads audit rows > 365d to Vercel Blob (filename audit-archive/YYYY-MM-DD.json) before deleting. Requires BLOB_READ_WRITE_TOKEN. Default = delete without archive.
SES_IP_POOL_DRY_RUN src/lib/providers/ses-ip-pool.ts true skips real AWS calls when creating / inspecting / deleting dedicated IP pools. Use in dev / CI where you don't want to provision AWS resources.
DLT_PROVIDER src/lib/providers/dlt.ts gupshup (default) or none. Selects the India DLT provider HTTP client. none records local rows without provider calls.
GUPSHUP_API_KEY / GUPSHUP_USER_ID src/lib/providers/dlt.ts Required when DLT_PROVIDER=gupshup.
DLT_ENFORCE src/lib/api/dlt-gate.ts false to bypass the send-time DLT template check for +91 recipients (dev / migration). Default true.
DLT_DRY_RUN src/lib/providers/dlt.ts true skips provider HTTP calls; rows land in submitted and the reconcile cron is a no-op.
LOG_LEVEL src/lib/log.ts One of debug, info, warn, error. Default info.
SENTRY_DSN src/lib/observability.ts Enables Sentry capture for warn / error log lines and logError(...) calls. Requires npm install @sentry/nextjs. Unset = no-op.

Notes

  • Rate limiting is gated on Upstash envs — absent Upstash envs, all API calls pass without throttling. Per-plan limits (free/pro/enterprise) auto-select based on organizations.plan_status.
  • Test-mode API keys (sok_test_*) skip provider calls and usage limits — no AWS creds needed to test key plumbing.
  • OAuth providers are opt-in — Google/GitHub sign-in buttons render only when the respective client_id + secret pair is set.
  • Cron endpoints are open without CRON_SECRET — don't deploy to prod without it.
  • Vercel: use vercel env pull .env.local to sync from project env.