Variables de entorno
Todas las variables: obligatorias y opcionales, frontend y backend.
En esta página
- Frontend: mínimo
- Backend compartido: mínimo
- Frontend y backend: todas las variables
- Frontend: núcleo
- Frontend: conexión con el backend compartido
- Sesiones y MFA
- Cifrado, assets, adjuntos y retención
- Correo, webhooks y cron
- Rate limit (Upstash)
- Almacenamiento
- IA
- OAuth y push
- Límites de envío y Elixir
- Marca y desarrollo
- Backend compartido
- Variables que ya no existen
Esta página es la referencia completa. Cada variable se verificó contra el código (nombre, valor por defecto y qué pasa si falta) y un test impide listar variables inexistentes. No pongas valores reales en el repositorio: usa las variables del proveedor (Vercel, etc.).
Cómo leer las tablas
Obligatoria: sin ella no arranca o falla. Condicional: obligatoria solo si usas esa función (por ejemplo Google, o el registro en producción). Opcional: hay un valor por defecto o la función se desactiva. En "Por defecto", "—" significa que no hay valor por defecto.
Frontend: mínimo#
# .env (frontend) — mínimo para arrancar. Todos los valores son marcadores de posición.
DATABASE_URL="postgresql://USUARIO:CONTRASENA@HOST:5432/bloomx"
NEXTAUTH_SECRET="<cadena-aleatoria-larga-propia-de-esta-instancia>" # openssl rand -base64 48
RESEND_API_KEY="re_xxxxxxxx"
NEXT_PUBLIC_APP_URL="https://mail.tu-dominio.com"
NEXT_PUBLIC_BACKEND_URL="https://backend.tu-dominio.com"
TOP_DOMAIN="tu-dominio.com"
REGISTRATION_KEY="<clave-para-el-alta-de-usuarios>"
ADMIN_EMAILS="admin@tu-dominio.com"# Recomendado en producción (frontend)
S3_ENDPOINT="https://..." S3_REGION="auto" S3_ACCESS_KEY="..." S3_SECRET_KEY="..." S3_BUCKET="bloomx-uploads"
DATA_ENCRYPTION_KEY="<clave-dedicada-distinta-de-NEXTAUTH_SECRET>"
ENCRYPTION_REQUIRE_DEDICATED_KEY="true"
CRON_SECRET="<cadena-aleatoria>"
UPSTASH_REDIS_REST_URL="https://..." UPSTASH_REDIS_REST_TOKEN="..."
BLOOMX_DOMAIN_PRIVATE_KEY="<salida de node scripts/gen-domain-keypair.mjs>"
# Opcional por organizador: firma de los webhooks de Resend
WEBHOOK_SECRET="whsec_..." RESEND_WEBHOOK_SECRET="whsec_..."Cada frontend tiene SU NEXTAUTH_SECRET
No se comparte con el backend ni con otros frontends. Si lo rotas, se cierran todas las sesiones; fija antes MFA_RECOVERY_PEPPER (y DATA_ENCRYPTION_KEY si usabas la reserva) para no perder los códigos de recuperación ni el contenido cifrado.
Backend compartido: mínimo#
# .env (backend compartido) — marcadores de posición
DATABASE_URL="postgresql://USUARIO:CONTRASENA@HOST:5432/bloomx_backend"
NEXT_PUBLIC_BACKEND_URL="https://backend.tu-dominio.com"
B2_ENDPOINT="https://..." B2_REGION="..." B2_BUCKET="..." B2_ACCESS_KEY="..." B2_SECRET_KEY="..."
DATA_ENCRYPTION_KEY="<64 hex o base64 de 32 bytes>" # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
ADMIN_EMAIL="plataforma@tu-dominio.com" ADMIN_PASSWORD="<contraseña>"
STORAGE_PUBLIC_PREFIXES="public/,logos/"
# Opcional: puente backend -> frontend (Organizer / services.mail)
# BACKEND_SIGNING_PRIVATE_KEY="<PEM PKCS8>"
# NO definir NEXTAUTH_SECRET, INTERNAL_SECRET, EXTENSION_HOOKS_SECRET ni FRONTEND_INTERNAL_URL en el backend: ya no se leen.Sin DATA_ENCRYPTION_KEY el backend guarda la clave de Resend de cada dominio y las credenciales de extensiones sin cifrar (en producción solo emite un aviso y PUT /api/extension/settings responde 503).
Frontend y backend: todas las variables#
La columna Dónde indica si la variable se lee en el frontend, en el backend o en ambos.
Frontend: núcleo#
Sin DATABASE_URL, NEXTAUTH_SECRET y RESEND_API_KEY el frontend no funciona.
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| DATABASE_URL | Frontend | Obligatoria | — | Cadena de conexión PostgreSQL (pg y Prisma). Sin ella db:ensure solo avisa y el pool lanza error. |
| NEXTAUTH_SECRET | Frontend | Obligatoria | — | Secreto propio de esta instancia. Firma el JWT de sesión y de él se derivan por HKDF la clave interna, las URLs firmadas, los tokens de baja y cancelación y (como reserva) el cifrado. En producción sin él, falla. |
| RESEND_API_KEY | Frontend | Obligatoria | — | Clave de la API de Resend: envío, lectura del correo entrante y adjuntos. |
| NEXT_PUBLIC_APP_URL | Frontend | Opcional | https://bloomx.arubik.dev | URL pública https de esta instancia. Callbacks OAuth, enlaces de baja y de mensajes sellados, cadena de cron y origen firmado hacia el backend. Fíjala siempre en producción. |
| NEXT_PUBLIC_BACKEND_URL | Frontend | Opcional | https://backend.bloomx.arubik.dev | URL del backend compartido (configuración, extensiones, login de admin, registro de dominio). Ponla siempre con https. |
| TOP_DOMAIN | Ambos | Opcional | cabecera Host | Dominio (tenant) de esta instancia y dominio del correo del sistema (noreply@…). En el backend, si existe, prevalece sobre ?domain en /api/config. |
| REGISTRATION_KEY | Frontend | Condicional | dev-secret | Clave que exige /api/register. En producción, si falta o vale dev-secret, el registro responde 403. |
Frontend: conexión con el backend compartido#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| BLOOMX_DOMAIN_PRIVATE_KEY | Frontend | Opcional | — | Clave privada Ed25519 (PEM PKCS8 en una línea o base64). Con ella los proxies al backend van firmados; sin ella se usa el modo legado. Genérala con node scripts/gen-domain-keypair.mjs. |
| BLOOMX_ACCEPT_BACKEND_SIGNATURE | Frontend | Opcional | true | Acepta la firma ANTIGUA del backend (legado deprecado) en /api/internal/**. Pon false para aceptar solo executionGrant. |
| BLOOMX_GRANT_TTL_SECONDS | Frontend | Opcional | 120 | Vida de cada executionGrant (30 a 900 s). |
| BLOOMX_GRANT_MAX_USES | Frontend | Opcional | 300 | Llamadas máximas a los servicios del host por executionGrant (por proceso). |
| BLOOMX_BACKEND_PUBLIC_KEY | Frontend | Opcional | descubrimiento | DEPRECADA (legado). Clave pública del backend para verificar llamadas antiguas firmadas por el backend. Ya no hace falta: las llamadas nuevas llevan una executionGrant firmada con la clave de ESTA instancia (ext.grants.v1). |
| INTERNAL_SECRET | Frontend | Opcional | derivada de NEXTAUTH_SECRET | Solo compatibilidad: si la defines se acepta como clave interna. No hace falta. |
| EXTENSION_HOOKS_DISABLED | Frontend | Opcional | false | true desactiva la llamada a hooks EMAIL_PRE_SEND del backend. |
| EXTENSION_HOOKS_FAIL_CLOSED | Frontend | Opcional | false | true: si el backend no responde, el correo no se envía (por defecto se envía y se registra el fallo). |
Sesiones y MFA#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| ADMIN_EMAILS | Frontend | Opcional | — | Semilla y rescate de administración (correos separados por coma): esas cuentas son permission_level 4 «fijado por entorno», con MFA obligatorio; no se pueden degradar desde la consola ni la CLI (solo quitándolas de la variable). Los demás niveles 0-4 se gestionan desde /admin/permissions y bloomx perms (Admin CLI). Retrocompatible: si solo defines esta variable, todo funciona como antes. |
| ADMIN_EMAILS_LOCKED | Frontend | Opcional | false | true = modo solo-entorno: la consola y la CLI no gestionan niveles; el nivel efectivo es 4 si el correo está en ADMIN_EMAILS y 0 si no (las concesiones de consola se ignoran). |
| ADMIN_LOCKOUT_RESET | Frontend | Opcional | — | Rescate: correos (coma) cuyo bloqueo de acceso privilegiado por «pelea de sesiones» se levanta al siguiente acceso. Úsalo si queda bloqueado el único superadmin y quita la variable después (Admin CLI). |
| SESSION_TTL_SECONDS | Frontend | Opcional | 86400 | Inactividad de la sesión (deslizante). Mín. 300, máx. 30 días. |
| SESSION_ABSOLUTE_MAX_SECONDS | Frontend | Opcional | 1209600 | Tope absoluto desde el login (14 días). Mín. 3600, máx. 90 días. |
| SESSION_ALLOW_LEGACY_TOKENS | Frontend | Opcional | true | false rechaza ya los tokens antiguos sin jti. |
| SESSION_REVOCATION_CACHE_MS | Frontend | Opcional | 5000 | Caché por instancia de la comprobación de revocación. |
| SESSION_COOKIE_HOST_PREFIX | Frontend | Opcional | activo en producción | Cookie __Host-next-auth.session-token. Pon 0 para desactivar el prefijo. |
| SESSION_COOKIE_LEGACY_READ | Frontend | Opcional | true | Sigue leyendo la cookie antigua sin prefijo. Pon 0 cuando ya no queden sesiones previas (máx. 30 días). |
| MFA_ENFORCE_ADMIN | Frontend | Opcional | true | false no exige MFA a ADMIN_EMAILS. |
| MFA_REQUIRED_ALL | Frontend | Opcional | false | true exige MFA a todos los usuarios. |
| MFA_ISSUER | Frontend | Opcional | BRAND_NAME o Bloomx | Nombre del emisor en la app TOTP. |
| MFA_RECOVERY_PEPPER | Frontend | Opcional | NEXTAUTH_SECRET | Pepper de los códigos de recuperación. Fíjalo si vas a rotar NEXTAUTH_SECRET. |
| GOOGLE_ALLOW_SIGNUP | Frontend | Opcional | false | En producción, permite crear cuentas nuevas mediante Google. |
| MOLT_SIGNING_KEY | Frontend | Opcional | derivada de NEXTAUTH_SECRET | Clave de los tokens de la API molt. |
| MOLT_CONNECT_SECRET | Frontend | Opcional | — | Si se define, /api/molt/auth/connect exige este secreto en el cuerpo. |
Cifrado, assets, adjuntos y retención#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| DATA_ENCRYPTION_KEY | Ambos | Opcional | NEXTAUTH_SECRET (frontend) | Clave de cifrado en reposo. Frontend: AES-256-GCM v3 (reserva NEXTAUTH_SECRET). Backend: 64 hex o base64 de 32 bytes; sin ella los secretos se guardan sin cifrar. |
| DATA_ENCRYPTION_KEY_ID | Frontend | Opcional | k1 | Id de la clave vigente (rotación). |
| DATA_ENCRYPTION_KEYS_PREVIOUS | Frontend | Opcional | — | Claves anteriores para descifrar: k0:secreto,k1:otro. |
| ENCRYPTION_REQUIRE_DEDICATED_KEY | Frontend | Opcional | false | true obliga a definir DATA_ENCRYPTION_KEY en producción. |
| ENCRYPTION_WRITE_FORMAT | Frontend | Opcional | v3 | Formato de escritura (v2 = rollback). |
| ACCOUNT_TOKENS_LAZY_MIGRATE | Frontend | Opcional | true | false desactiva la migración perezosa de tokens OAuth al formato vigente. |
| ASSET_SIGNING_KEY | Frontend | Opcional | derivada de NEXTAUTH_SECRET | Clave HMAC de las URLs firmadas de /api/assets. |
| ASSET_URL_TTL_SECONDS | Frontend | Opcional | 3600 | Vigencia de URLs de adjuntos recibidos. |
| ASSET_UPLOAD_URL_TTL_SECONDS | Frontend | Opcional | 2592000 | Vigencia de URLs de subidas (30 días). |
| ASSET_UNSIGNED_INBOUND | Frontend | Opcional | owner | Política de enlaces sin firma de adjuntos entrantes: allow | owner | deny. |
| ASSET_UNSIGNED_UPLOADS | Frontend | Opcional | allow | Política de enlaces sin firma de subidas: allow | owner | deny. |
| AV_SCAN_URL | Frontend | Opcional | — | URL del antivirus (ClamAV REST). Sin ella no hay escaneo. |
| AV_SCAN_TOKEN | Frontend | Opcional | — | Bearer del antivirus. |
| AV_SCAN_FIELD | Frontend | Opcional | file | Nombre del campo multipart. |
| AV_SCAN_TIMEOUT_MS | Frontend | Opcional | 8000 | Timeout del escaneo. |
| AV_SCAN_MAX_BYTES | Frontend | Opcional | 26214400 | Tamaño máximo escaneable (25 MB); mayores se omiten. |
| AV_FAIL_MODE | Frontend | Opcional | open | open: acepta si el AV falla; closed: bloquea. |
| INBOUND_BLOCK_DANGEROUS_EXT | Frontend | Opcional | true | false no bloquea extensiones peligrosas en el correo entrante. |
| RETENTION_SPAM_DAYS | Frontend | Opcional | 30 | Días de retención de spam (0 = no purga). |
| RETENTION_TRASH_DAYS | Frontend | Opcional | 0 | Retención de la papelera (0 = desactivado). |
| RETENTION_RAW_DAYS | Frontend | Opcional | 0 | Retención del raw.json del webhook (0 = desactivado). |
| AUDIT_RETENTION_DAYS | Frontend | Opcional | 365 | Retención de AuditEvent (0 = no purga). |
| AUDIT_DB | Frontend | Opcional | activo | off audita solo a stdout. |
| RETENTION_BATCH | Frontend | Opcional | 200 | Lote por pasada (tope 1000). |
| SECURE_MESSAGE_TTL_DAYS | Frontend | Opcional | 30 | TTL máximo de mensajes sellados. |
| SECURE_MESSAGE_ENABLED | Frontend | Opcional | true | false desactiva los mensajes sellados. |
Correo, webhooks y cron#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| WEBHOOK_SECRET | Frontend | Opcional | — | Secreto whsec_… del webhook entrante de Resend. Opcional por organizador: con él se exige firma Svix válida en /api/webhooks/resend; sin él se acepta sin firma (solo un aviso en el log). |
| RESEND_WEBHOOK_SECRET | Frontend | Opcional | — | Igual para el webhook de eventos (rebotes y quejas) /api/webhooks/resend-events. Opcional por organizador. |
| CRON_SECRET | Frontend | Opcional | — | Bearer de los crons (/api/cron/run global, /api/cron/elixir, /api/admin/retention). Vercel lo envía solo si la variable existe en el proyecto. |
| UNSUBSCRIBE_SECRET | Frontend | Opcional | NEXTAUTH_SECRET | Secreto de los tokens de baja (RFC 8058). |
| APPOINTMENT_CANCEL_SECRET | Frontend | Opcional | NEXTAUTH_SECRET | Secreto de los enlaces de cancelación de citas. |
| MAX_SENDS_PER_HOUR | Frontend | Opcional | 200 | Máximo de envíos normales por hora y usuario (429 si se supera). |
| SPAM_SCORE_THRESHOLD | Ambos | Opcional | 60 | Umbral inicial del filtro de spam mientras no haya configuración guardada en la consola (/admin/spam); entonces el nivel pasa a «personalizado». |
| ENABLE_AUTO_SPAM_DETECTION | Frontend | Opcional | true | false desactiva el filtro de spam mientras no haya configuración guardada en la consola (la lista de bloqueo sigue activa). |
Rate limit (Upstash)#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| UPSTASH_REDIS_REST_URL | Frontend | Opcional | — | URL REST de Upstash Redis. Con la URL y el token el rate limit es global; sin ellos es por instancia. |
| UPSTASH_REDIS_REST_TOKEN | Frontend | Opcional | — | Token REST de Upstash. |
| RATE_LIMIT_ON_ERROR | Frontend | Opcional | memory | Si Redis falla: memory cuenta en memoria; open deja pasar. |
| RATE_LIMIT_REDIS_TIMEOUT_MS | Frontend | Opcional | 800 | Timeout de Redis (100–5000). |
Almacenamiento#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| S3_ENDPOINT | Frontend | Condicional | — | Endpoint S3-compatible (AWS, R2, MinIO, B2). Sin S3_ACCESS_KEY o S3_BUCKET el almacenamiento cae a disco local (.gemini/storage): solo para desarrollo. |
| S3_REGION | Frontend | Condicional | us-east-1 | Región (o auto). |
| S3_ACCESS_KEY | Frontend | Condicional | — | Access key ID. |
| S3_SECRET_KEY | Frontend | Condicional | — | Secret access key. |
| S3_BUCKET | Frontend | Condicional | — | Nombre del bucket. |
| S3_SSE | Frontend | Opcional | — | Cifrado del lado del proveedor: AES256 o aws:kms. |
| B2_ENDPOINT | Ambos | Condicional | — | Endpoint de Backblaze B2. Frontend: alias heredado de S3_*. Backend: obligatorio para almacenar extensiones y archivos. |
| B2_REGION | Ambos | Condicional | — | Región de B2. |
| B2_BUCKET | Ambos | Condicional | — | Bucket de B2. |
| B2_ACCESS_KEY | Ambos | Condicional | — | Access key de B2. |
| B2_SECRET_KEY | Ambos | Condicional | — | Secret key de B2. |
IA#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| AI_PROVIDER | Ambos | Opcional | openai | HEREDADA/DEPRECADA. Proveedor del respaldo heredado; solo se usa si no hay configuración en /admin/ai. Migra: IA. |
| AI_KEY | Ambos | Opcional | — | HEREDADA/DEPRECADA. Clave del respaldo heredado; solo si no hay configuración en /admin/ai (se muestra aviso y nunca se mezcla). La clave se gestiona ahora cifrada desde la interfaz. Migra: IA. |
| AI_MODEL | Ambos | Opcional | gpt-3.5-turbo (frontend), gpt-4o-mini (backend) | HEREDADA/DEPRECADA. Modelo del respaldo heredado; se elige ahora en /admin/ai. Migra: IA. |
OAuth y push#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| NEXTAUTH_URL | Frontend | Condicional | — | Origen público para construir el redirect URI de Google. Necesaria si activas el login o la sincronización de Google. |
| GOOGLE_CLIENT_ID | Frontend | Opcional | — | OAuth de Google (login, Meet, calendario, contactos). |
| GOOGLE_CLIENT_SECRET | Frontend | Opcional | — | Secreto OAuth de Google. |
| ZOOM_CLIENT_ID | Frontend | Opcional | — | OAuth de Zoom. |
| ZOOM_CLIENT_SECRET | Frontend | Opcional | — | Secreto OAuth de Zoom. |
| GOOGLE_API_BASE | Frontend | Opcional | — | SOLO pruebas locales: base de la API de Google (también MEET_API_BASE, GOOGLE_TOKEN_URL, ZOOM_API_BASE, ZOOM_OAUTH_BASE). Se ignora en producción salvo hacia localhost. Ver Reuniones. |
| SLACK_CLIENT_ID | Frontend | Opcional | — | OAuth de Slack. |
| SLACK_CLIENT_SECRET | Frontend | Opcional | — | Secreto OAuth de Slack. |
| NOTION_CLIENT_ID | Frontend | Opcional | — | OAuth de Notion. |
| NOTION_CLIENT_SECRET | Frontend | Opcional | — | Secreto OAuth de Notion. |
| HUBSPOT_CLIENT_ID | Frontend | Opcional | — | OAuth de HubSpot. |
| HUBSPOT_CLIENT_SECRET | Frontend | Opcional | — | Secreto OAuth de HubSpot. |
| TRELLO_API_KEY | Frontend | Opcional | — | Application Key de Trello. |
| NEXT_PUBLIC_VAPID_PUBLIC_KEY | Frontend | Opcional | se genera y guarda en BD | Clave pública VAPID (notificaciones push). Con la pública y la privada se usan; si falta alguna se genera un par y se guarda en la tabla push_vapid_config. |
| VAPID_PRIVATE_KEY | Frontend | Opcional | — | Clave privada VAPID. |
| VAPID_SUBJECT | Frontend | Opcional | https://<dominio de la instancia> | Sujeto VAPID (mailto: o URL https). |
Límites de envío y Elixir#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| ELIXIR_BATCH_MAX | Frontend | Opcional | 50 | Filas por petición de envío (tope 100). |
| ELIXIR_BATCH_BUDGET_MS | Frontend | Opcional | 45000 | Presupuesto de tiempo por lote. |
| ELIXIR_SEND_INTERVAL_MS | Frontend | Opcional | 550 | Pausa entre envíos. |
| ELIXIR_MAX_ROWS_PER_HOUR | Frontend | Opcional | 5000 | Cuota de filas por hora (por instancia, en memoria). |
| MAX_BULK_ROWS | Frontend | Opcional | 5000 | Alias antiguo de ELIXIR_MAX_ROWS_PER_HOUR (es por hora, no por petición). |
| ELIXIR_MAX_CAMPAIGN_ROWS | Frontend | Opcional | 20000 | Filas máximas por campaña. |
Marca y desarrollo#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| BRAND_NAME | Frontend | Opcional | — | Nombre de marca en build (se copia a NEXT_PUBLIC_BRAND_NAME); también lo usa MFA. |
| BRAND_COLOR | Frontend | Opcional | — | Color de marca en build (NEXT_PUBLIC_BRAND_COLOR). |
| BRAND_LOGO | Frontend | Opcional | — | Logo en build (NEXT_PUBLIC_BRAND_LOGO). |
| NEXT_PUBLIC_DEFAULT_TIMEZONE | Frontend | Opcional | America/Lima | Zona horaria de las plantillas de calendario (también DEFAULT_TIMEZONE). |
| NEXT_PUBLIC_BLOOMX_THEME_OVERRIDE | Frontend | Opcional | — | Solo desarrollo: JSON de tema que sustituye el de /api/config. Ignorado en producción. |
Backend compartido#
| Variable | Dónde | Requisito | Por defecto | Descripción |
|---|---|---|---|---|
| DATABASE_URL | Backend | Obligatoria | — | PostgreSQL del backend (Prisma). También lo necesita sync-extensions.mjs. |
| ADMIN_EMAIL | Backend | Opcional | — | Super-admin de plataforma (Basic Auth de /api/admin/extensions). Sin ambas variables, siempre falla. |
| ADMIN_PASSWORD | Backend | Opcional | — | Contraseña del super-admin de plataforma. |
| ALLOW_OPEN_REGISTRATION | Backend | Opcional | abierto | false cierra /api/auth/register (despliegue privado). |
| BACKEND_SIGNING_PRIVATE_KEY | Backend | Opcional | — | DEPRECADA (legado). El backend compartido NO debe tener clave global. Solo sirve a instancias antiguas sin ext.grants.v1; las instancias nuevas no la necesitan (usan executionGrant). Se retirará. |
| BACKEND_CRON_SECRET | Backend | Opcional | — | Bearer del cron global de hooks CRON. Sin definir no existe esa vía. |
| EXTENSION_GLOBAL_ENV_FALLBACK | Backend | Opcional | — | Endurecimiento opcional del uso de variables globales por las extensiones: none lo desactiva, una lista separada por comas lo limita a esos nombres; sin definir, cualquier ENV_READ no reservado de plataforma. |
| EXTENSION_ALLOW_HTTP | Backend | Opcional | false | true permite http en el fetch de extensiones (no recomendado). |
| MARKETPLACE_THIRD_PARTY_ENABLED | Backend | Opcional | false | Interruptor de la publicación de extensiones de terceros. Solo el valor exacto true la enciende; apagado, /api/developer/** (salvo overview, withdraw y yank) responde 503 marketplace_disabled y las dev.* solo corren en el dominio de su autor. Ver Modelo del sandbox. |
| EXT_SANDBOX_MAX_WORKERS | Backend | Opcional | 8 | Workers simultáneos del sandbox (1–64). |
| STORAGE_PUBLIC_PREFIXES | Backend | Opcional | sin lista blanca | Prefijos del bucket servibles por /api/storage (coma). Recomendado en producción. |
| PAYPAL_ENV | Backend | Opcional | sandbox | sandbox o live. Un valor inválido apaga los pagos (503 payments_not_configured); nunca cae a live. Ver PayPal. |
| PAYPAL_CLIENT_ID | Backend | Opcional | — | Client id de la app REST de PayPal. Sin credenciales los pagos responden 503. |
| PAYPAL_CLIENT_SECRET | Backend | Opcional | — | Secreto de la app REST de PayPal (solo en el entorno de la plataforma). |
| PAYPAL_WEBHOOK_ID | Backend | Opcional | — | Id del webhook de PayPal; obligatorio para verificar la firma de los eventos. |
| PAYPAL_OIDC_REDIRECT_URI | Backend | Opcional | — | redirect_uri exacta de Log in with PayPal: https://<backend>/api/payments/paypal/link/callback. |
| PAYMENTS_CRON_SECRET | Backend | Opcional | — | Bearer (mínimo 24 caracteres) de /api/cron/payments. En Vercel, CRON_SECRET con el mismo valor. |
| PAYMENTS_DEVELOPER_SHARE_BPS | Backend | Opcional | 7000 | Parte del desarrollador en puntos base (7000 = 70 %); el resto es de la plataforma. |
| PAYMENTS_MIN_PRICE_CENTS | Backend | Opcional | 200 | Precio mínimo por extensión, en centavos USD. |
| PAYMENTS_MAX_PRICE_CENTS | Backend | Opcional | 100000 | Precio máximo por extensión, en centavos USD. |
| PAYMENTS_HOLD_DAYS | Backend | Opcional | 14 | Días de retención antes de poder pagar al desarrollador. |
| PAYMENTS_PAYOUT_MIN_CENTS | Backend | Opcional | 1000 | Pago mínimo al desarrollador, en centavos. |
| PAYMENTS_PAYOUT_MAX_CENTS | Backend | Opcional | 500000 | Pago máximo por ciclo, en centavos. |
| PAYMENTS_ACCOUNT_SWITCH_HOURS | Backend | Opcional | 24 | Horas durante las que los pagos pendientes siguen a la cuenta PayPal anterior. |
| PAYMENTS_GRACE_DAYS | Backend | Opcional | 3 | Días de gracia tras un cobro de suscripción fallido. |
| PAYMENTS_RENEWAL_BUFFER_HOURS | Backend | Opcional | 24 | Horas de holgura tras la renovación antes de pausar (webhook tardío). |
| PAYMENTS_TERMS_VERSION | Backend | Opcional | 2026-10 | Versión vigente de los términos del desarrollador. |
| PLATFORM_RESEND_API_KEY | Backend | Opcional | — | Clave de Resend de la plataforma para correos de revisión, cuenta y cobros. |
| PLATFORM_MAIL_FROM | Backend | Opcional | — | Remitente de los correos de la plataforma (BloomX <billing@tu-dominio>). |
| OPENAI_API_KEY | Backend | Opcional | — | HEREDADA/DEPRECADA. El backend compartido ya no usa clave de IA global: su uso emite un aviso en logs y solo se conserva por compatibilidad con instancias antiguas sin el endpoint del puente. Migra cada instancia a /admin/ai: IA. |
Variables que ya no existen#
Aparecían en documentación antigua y el código no las lee: COOKIE_SECRET, EXPANSION_SECRET, AI_OPENAI_API_KEY, AI_GEMINI_API_KEY, AI_ANTHROPIC_API_KEY, AI_COHERE_API_KEY (la IA se configura en /admin/ai; AI_KEY/AI_PROVIDER/AI_MODEL son solo respaldo heredado, ver IA),SLACK_SIGNING_SECRET, EXPANSION_CRM_URL, EXPANSION_CRM_API_KEY, EXPANSION_WEBHOOK_URL y TRELLO_SECRET. Entre frontend y backend tampoco se usan EXTENSION_HOOKS_SECRET ni FRONTEND_INTERNAL_URL. En el backend RESEND_API_KEY no se lee: la clave de Resend llega en register-domain y se guarda cifrada por dominio.