Skip to content

Environment Variables

Applies to: All subscriptions

Purpose

Provide the complete reference for host-level configuration: what each setting controls, what happens if it is wrong, and which subsystem stops working. This is the page an administrator opens when something is misconfigured and the log is unhelpful.

Audience

System administrators and implementation engineers. Integration developers, for the authentication and write-back groups.

Prerequisites

Reference

Settings live in an environment file read by the API and worker at startup. Every change requires a restart of the affected process.

Treat this file as a credential store: restrict its permissions to the service account and administrators, keep it out of source control, and own the rotation of what it holds.

Core application

Setting Purpose Note
NODE_ENV Runtime mode production in production. Development mode changes error verbosity and logging
PORT API listening port 5003 in the reference deployment. A built-in fallback exists and must not be relied on — if the proxy and service disagree, the symptom is HTTP 502 with a silent application log
APP_NAME Display name in logs Cosmetic
APP_BASE_URL The application's own public URL Used to build links. Wrong here means emails and documents point at the wrong environment
CORS_ORIGINS Browser origins permitted to call the API Only needed when the front end is on a different origin. Never a wildcard
LOG_LEVEL Log verbosity info in production. debug is for diagnosis and generates a lot of volume
LOG_PRETTY Human-readable log formatting Off in production, where logs are machine-collected

Database

Setting Purpose Failure if wrong
DB_SERVER Host or address, with instance name if applicable API refuses to start
DB_PORT Database port Connection timeout
DB_DATABASE Database name Startup failure, often misread as a credential problem
DB_USER / DB_PASSWORD Application login Authentication failure at startup
DB_ENCRYPT Encrypt the connection Should be enabled. Disabling puts credentials and data in clear text
DB_TRUST_SERVER_CERT Whether to accept the server certificate without validation A deliberate, recorded decision. Acceptable only inside a controlled network
DB_POOL_MIN / DB_POOL_MAX Connection pool bounds Too low starves under load; too high exhausts database connections. Tune only against measurement
DB_CONNECTION_TIMEOUT_MS Connection establishment timeout Too low produces spurious startup failures on a busy instance
DB_REQUEST_TIMEOUT_MS Per-query timeout Too low fails long reports; too high hides a runaway query
DB_POOL_IDLE_TIMEOUT_MS Idle connection lifetime Rarely needs changing
DB_APP_NAME Application name in database sessions Useful for identifying Complifly connections when diagnosing

Authentication and identity

Setting Purpose Failure if wrong
JWT_SECRET Signs and verifies session tokens Users cannot sign in. Changing it invalidates every existing session — a deliberate act, not a routine one. Must be long, random, and different per environment
AZURE_TENANT_ID Your own identity tenant — used for user sign-in, and to recognise ERP app registrations that live in it. It is not the tenant an ERP token must come from; that is recorded per connection User sign-in fails
AZURE_CLIENT_ID Application registration identifier for user sign-in Sign-in token validation fails
AZURE_API_AUDIENCE Accepted token audience values for machine tokens Valid tokens rejected. Both the application identifier URI and the bare identifier may be needed, depending on token version
AZURE_REQUIRED_ROLE Application role a machine token must carry Authenticated calls rejected as unauthorised
AZURE_API_APP_ID The API application registration customers grant admin consent to. That registration must be multi-tenant, or no customer directory can consent Consent links cannot be generated. The administration screen says so rather than failing later
ERP_CONSENT_REDIRECT_URI Where Microsoft Entra returns a customer's administrator after consent Consent fails at the customer's end with an AADSTS error you never see
GOOGLE_CLIENT_ID Social sign-in, where enabled Social sign-in fails
OTP_EXPIRY_MINUTES One-time code lifetime Too short frustrates users; too long weakens the control
OTP_MAX_ATTEMPTS Attempts before lockout Balance usability against brute-force resistance
OTP_RESEND_COOLDOWN_SECONDS Minimum interval between code requests Prevents message flooding
PAN_ENCRYPTION_KEY Encrypts stored identity numbers Losing this makes existing encrypted values unreadable. Back it up separately from the database, or a restore recovers rows nobody can read

PAN_ENCRYPTION_KEY deserves particular care. It is the one setting whose loss is not recoverable from a database backup, because the backup contains only the ciphertext.

ERP_CONSENT_REDIRECT_URI must match Entra character for character. This value is registered as a redirect URI on the API application in Microsoft Entra. If the two disagree by so much as a trailing slash, consent fails inside the customer's directory, where the only diagnostic is an AADSTS code on their screen.

It is therefore set explicitly rather than derived from the domain map: a hostname change must be a deliberate, paired edit — this variable and the Entra registration, in the same change. Moving the public address without updating Entra breaks onboarding for every new customer while leaving existing ones working, so nothing alerts you. An ERP token is not validated against AZURE_TENANT_ID. Each connection records the customer's own directory, and the token is checked against that. This is the setting most often misread when an integration is refused — widening or changing it does not admit a customer's ERP, and never should.

GSP providers

Setting group Purpose
PROVIDER The default provider for this deployment
WEBTEL_* Webtel credentials and per-operation endpoint URLs
MI_* Masters India credentials, base URLs and timeout
EINV_USER / EINV_PASS e-Invoice service credentials
EF_USER / EF_PASS e-Way Bill service credentials
GSP_CONFIG_CACHE_TTL_MS How long provider configuration is cached

Provider endpoint URLs are supplied by the provider and differ between sandbox and production. Mixing them is the mechanism by which a test document reaches the live government system.

See GSP Configuration for assignment and testing.

Mail

Setting Purpose Failure if wrong
SMTP_HOST / SMTP_PORT Mail server No notifications, no password reset, no one-time codes. Users are locked out with no visible cause
SMTP_SECURE Whether the connection is implicitly encrypted Handshake failure
SMTP_USER / SMTP_PASS Mail credentials Authentication failure at send time, not at startup
SMTP_FROM Sender address Messages rejected or filtered as spam if it fails sender policy checks
AZURE_COMMUNICATION_CONNECTION_STRING Vendor mail service, as an alternative to SMTP
AZURE_EMAIL_SENDER_ADDRESS Sender address for the vendor mail service

Mail failures are the most under-appreciated configuration fault in the product. They do not surface at startup, they produce no error in the interface, and the symptom reaching support is "a user cannot log in".

Background jobs and queue

Setting Purpose Note
JOBS_USE_QUEUE Whether background work is queue-backed When enabled, Redis becomes a hard dependency
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD Queue connection Silent failure: jobs enqueue and are never consumed. The interface looks entirely healthy
WORKER_CONCURRENCY Parallel jobs per worker Higher throughput, higher memory. Raise only against measurement
FILE_UPLOAD_DIR Where uploaded files are written Must be writable by the service account and included in backup planning
MAX_FILE_SIZE_MB Largest accepted upload Must align with the proxy's body limit, or the proxy rejects first and the message is unhelpful

IRN submission

Setting Purpose
IRN_SUBMIT_MAX_ATTEMPTS Retry attempts against the provider
IRN_SUBMIT_BASE_DELAY_MS Base delay for backoff between attempts
INGEST_IN_FLIGHT_TIMEOUT_MS How long an in-flight ingest may remain unresolved

Retries protect against transient network faults, not against rejections. A rejected document is rejected deterministically; retrying it consumes billed calls to no purpose.

e-Way Bill

Setting Purpose
EWB_EXPIRY_ALERTS_ENABLED Whether approaching-expiry alerts are raised
EWB_EXPIRY_HORIZON_HOURS How far ahead to look. Set to the customer's real dispatch lead time
EWB_PRINT_HORIZON_MONTHS How far back printed bills are retrievable

ERP write-back

Off by default. When enabled, these govern delivery behaviour:

Setting Purpose
ERP_WRITEBACK_ENABLED Master switch for the deployment. Enforced at emission — with this off, no outbound event is stored for anyone, and enabling it does not backfill history
ERP_WRITEBACK_BATCH_SIZE Events dispatched per cycle
ERP_WRITEBACK_DISPATCH_INTERVAL_MS How often dispatch runs
ERP_WRITEBACK_LEASE_SEC How long a worker holds a claim on an event
ERP_WRITEBACK_CIRCUIT_THRESHOLD Consecutive failures before the circuit opens
ERP_WRITEBACK_CIRCUIT_COOLDOWN_SEC / ..._CAP_SEC Cooldown after opening, and its ceiling
ERP_WRITEBACK_RETENTION_ENABLED / ..._DAYS How long delivered events are retained
ERP_WRITEBACK_DEAD_RETENTION_DAYS How long dead-lettered events are retained. Must exceed your realistic reaction time, or evidence is purged before anyone investigates
ERP_WRITEBACK_RAW_PAYLOAD_DAYS Retention of raw payloads

Three things must all be true before a single event is recorded. This variable is only the first of them, and the other two are not environment settings at all:

  1. ERP_WRITEBACK_ENABLED for the deployment (here).
  2. The ERP_WRITEBACK_ENABLED feature flag on the specific GSTIN — see Feature Flags.
  3. An active subscription for that ERP connection and GSTIN — see Write-back API.

All three are enforced at emission, so a gap in any one of them means the event is never written — not queued, not skipped, not delayed. Nothing errors on either side. If an ERP reports that it receives no events while everything "looks enabled", check all three before investigating delivery. | ERP_WRITEBACK_ALERTS_ENABLED / ..._SUPPORT_EMAIL | Failure alerting and its recipient | | ERP_WRITEBACK_ALLOW_INSECURE_URL | Permits a non-HTTPS endpoint. Never enable in production | | ERP_WRITEBACK_EMIT_ONLY | Emit events without dispatching, for a pull-based consumer | | ERP_WRITEBACK_RECONCILE_ENABLED / ..._INTERVAL_MS / ..._LOOKBACK_DAYS / ..._CAP | Reconciliation sweep for events that should have been emitted |

Verification caching

Setting Purpose
VERIFY_CACHE_ENABLED Whether verification results are cached rather than re-fetched
VERIFY_CACHE_TTL_GSTIN_DAYS Staleness window for registration status
VERIFY_CACHE_TTL_PAN_DAYS Staleness window for identity verification
VERIFY_CACHE_TTL_UDYAM_DAYS Staleness window for enterprise registration

These directly control the trade-off between provider cost and data freshness. A counterparty's registration status can change after it was cached — shorten the window where that risk matters, lengthen it where it does not.

Other

Setting Purpose
FEATURE_CACHE_TTL_MS How long per-GSTIN feature flags are cached. Explains why a flag change takes a moment to appear
SCHEMA_GUARD Startup schema verification. Leave enabled — disabling it restores the failure mode it exists to prevent
FVU_JAR_PATH / TDS_OUT_DIR TDS return validation tooling and output directory
DOTENV_PATH Alternative configuration file location

Complete reference

The sections above group the settings you will actually reach for, with the reasoning behind each. This table is the exhaustive list — every variable the backend reads, generated from the source so it cannot fall behind a release.

Treat an unfamiliar variable here as a default you are accepting rather than a setting you are missing. Most of them should stay untouched.

Every non-GSP variable this build reads, with the default that applies when you do not set it. GSP endpoints and credentials are in GSP Configuration.

Variable Default Read by
APP_BASE_URL http://localhost:8080 routes/auth.routes.js, services/azure-email.service.js
APP_NAME GST Backend API server.js
AZURE_API_APP_ID none routes/erp-connection.routes.js
AZURE_API_AUDIENCE empty string middleware/erpAuth.middleware.js, routes/erp-connection.routes.js
AZURE_CLIENT_ID none services/social-auth.service.js
AZURE_COMMUNICATION_CONNECTION_STRING none services/azure-email.service.js, services/notifications/ewbExpiryAlert.service.js
AZURE_EMAIL_SENDER_ADDRESS none services/azure-email.service.js, services/notifications/ewbExpiryAlert.service.js
AZURE_REQUIRED_ROLE Invoice.Post middleware/erpAuth.middleware.js
AZURE_TENANT_ID empty string middleware/erpAuth.middleware.js, services/social-auth.service.js
CORS_ORIGINS http://localhost:8080 server.js
DB_APP_NAME einvoice-service config/db.config.js
DB_CONNECTION_TIMEOUT_MS 15000 config/db.config.js
DB_DATABASE empty string config/db.config.js
DB_ENCRYPT false config/db.config.js
DB_PASSWORD Secret — no default config/db.config.js
DB_POOL_IDLE_TIMEOUT_MS 30000 config/db.config.js
DB_POOL_MAX 20 config/db.config.js
DB_POOL_MIN 4 config/db.config.js
DB_PORT 1433 config/db.config.js
DB_REQUEST_TIMEOUT_MS 30000 config/db.config.js
DB_SERVER empty string config/db.config.js
DB_TRUST_SERVER_CERT true config/db.config.js
DB_USER empty string config/db.config.js
DOTENV_PATH none config/db.config.js, config/mastersIndia.config.js +9
EF_PASS none config/nic.config.js
EF_USER none config/nic.config.js
EINV_PASS none config/nic.config.js
EINV_USER none config/nic.config.js
ERP_CONSENT_REDIRECT_URI none routes/erp-connection.routes.js
ERP_WRITEBACK_ALERTS_ENABLED false services/integration/alerter.service.js
ERP_WRITEBACK_ALLOW_INSECURE_URL false services/integration/egressGuard.js
ERP_WRITEBACK_BACKFILL_MAX_DOCS none services/integration/backfill.service.js
ERP_WRITEBACK_BATCH_SIZE none services/integration/dispatcher.service.js
ERP_WRITEBACK_CIRCUIT_COOLDOWN_CAP_SEC none services/integration/circuit.service.js
ERP_WRITEBACK_CIRCUIT_COOLDOWN_SEC none services/integration/circuit.service.js
ERP_WRITEBACK_CIRCUIT_THRESHOLD none services/integration/circuit.service.js
ERP_WRITEBACK_DEAD_RETENTION_DAYS none services/integration/retention.service.js
ERP_WRITEBACK_DISPATCH_INTERVAL_MS none services/integration/dispatcher.service.js
ERP_WRITEBACK_EMIT_ONLY false routes/writeback-subscription.routes.js, services/integration/dispatcherRunner.js +1
ERP_WRITEBACK_ENABLED false routes/writeback-subscription.routes.js, services/integration/dispatcherRunner.js +1
ERP_WRITEBACK_LEASE_SEC none services/integration/dispatcher.service.js
ERP_WRITEBACK_PURGE_BATCH none services/integration/retention.service.js
ERP_WRITEBACK_RAW_PAYLOAD_DAYS none services/integration/retention.service.js
ERP_WRITEBACK_RECONCILE_CAP none services/integration/reconciler.service.js
ERP_WRITEBACK_RECONCILE_ENABLED false services/integration/reconciler.service.js
ERP_WRITEBACK_RECONCILE_INTERVAL_MS none services/integration/reconciler.service.js
ERP_WRITEBACK_RECONCILE_LOOKBACK_DAYS none services/integration/reconciler.service.js
ERP_WRITEBACK_REQUEUE_STAGGER_SEC none services/integration/recovery.service.js
ERP_WRITEBACK_RETENTION_DAYS none services/integration/retention.service.js
ERP_WRITEBACK_RETENTION_ENABLED false services/integration/retention.service.js
ERP_WRITEBACK_RETENTION_INTERVAL_MS none services/integration/retention.service.js
ERP_WRITEBACK_SUPPORT_EMAIL empty string services/integration/alerter.service.js
ERP_WRITEBACK_WORKER_ID none services/integration/dispatcher.service.js
EWB_EXPIRY_ALERTS_ENABLED none services/notifications/ewbExpiryAlert.service.js
EWB_EXPIRY_HORIZON_HOURS none services/notifications/ewbExpiryAlert.service.js
EWB_PRINT_HORIZON_MONTHS 2 services/ewb/printEwbDoc.service.js
FEATURE_CACHE_TTL_MS 60000 services/feature.service.js
FILE_UPLOAD_DIR none routes/upload.routes.js
FVU_JAR_PATH none services/tds/fvuService.js
GOOGLE_CLIENT_ID none services/social-auth.service.js
GSP_CONFIG_CACHE_TTL_MS 60000 services/GSP/gspResolver.service.js
INGEST_IN_FLIGHT_TIMEOUT_MS none services/integration/ingestProtocol.service.js
IRN_SUBMIT_BASE_DELAY_MS none services/IRN/irnSubmit.service.js
IRN_SUBMIT_MAX_ATTEMPTS none services/IRN/irnSubmit.service.js
JOBS_USE_QUEUE false services/queue/index.js
JWT_SECRET Secret — no default middleware/auth.middleware.js, routes/auth.routes.js +3
LOG_LEVEL info config/logger.js
LOG_PRETTY empty string config/logger.js
MAX_FILE_SIZE_MB none routes/upload.routes.js
OTP_EXPIRY_MINUTES 5 services/otp.service.js
OTP_MAX_ATTEMPTS 5 services/otp.service.js
OTP_RESEND_COOLDOWN_SECONDS 60 services/otp.service.js
PAN_ENCRYPTION_KEY Secret — no default services/privacy/privacyService.js
PORT 5003 scripts/test_consent_direct.js, scripts/test_consent_gate.js +2
REDIS_HOST 127.0.0.1 services/queue/index.js
REDIS_PASSWORD Secret — no default services/queue/index.js
REDIS_PORT 6379 services/queue/index.js
SCHEMA_GUARD empty string config/schemaGuard.js
SMTP_FROM none services/email.service.js
SMTP_HOST none services/email.service.js
SMTP_PASS none services/email.service.js
SMTP_PORT 587 services/email.service.js
SMTP_SECURE none services/email.service.js
SMTP_USER none services/email.service.js
TDS_OUT_DIR none services/tds/fvuService.js
VERIFY_CACHE_ENABLED empty string services/verificationCache.service.js
VERIFY_CACHE_TTL_GSTIN_DAYS 7 services/verificationCache.service.js
VERIFY_CACHE_TTL_PAN_DAYS 90 services/verificationCache.service.js
VERIFY_CACHE_TTL_UDYAM_DAYS 90 services/verificationCache.service.js
WEBSITE_API_KEY_HASH Secret — no default routes/privacy.routes.js, scripts/setup_website_dpdp.js +1
WEBSITE_NOTICE_VERSION_ID none routes/privacy.routes.js, scripts/setup_website_dpdp.js +1
WEBSITE_PLAINTEXT_KEY Secret — no default scripts/test_website_dpdp.js
WEBSITE_TENANT_ID COMPLIFLY_WEBSITE routes/privacy.routes.js, scripts/test_website_dpdp.js
WORKER_CONCURRENCY 4 worker.js

94 variables. Generated from the process.env reads in the backend — do not edit by hand; run node tools/docs/gen-env-reference.js --write.

Validation

After editing the environment file:

Check Method Pass condition
File is valid Restart the API and read the startup log Starts cleanly
Restart actually happened Compare the process start time Recent. Editing without restarting is the most common "the change did nothing" cause
Worker restarted too Check the worker Restarted, if the setting affects background work
Database settings correct Application starts and screens load Connected
Port matches the proxy Request through the proxy HTTP 200, not 502
Provider settings correct Run the connection test Success
Mail works Trigger a password reset to a real mailbox Delivered
Queue works, if enabled Submit an upload Job completes rather than queuing indefinitely
Permissions restricted Inspect the file's permissions Readable only by the service account and administrators
Not in source control Check the repository Absent
Sandbox and production separated Inspect provider URLs per environment Non-production points only at sandbox

Troubleshooting

Symptom Cause Action
Change had no effect No restart, or the wrong process restarted Restart the API, and the worker if relevant
API will not start after an edit Malformed file, or a required value missing Read the startup log; it usually names the setting
HTTP 502 through the proxy Port mismatch between service and proxy Align them
Users cannot sign in after a change The token signing secret changed Every existing session is invalidated. Expected, but only if intended
Encrypted identity values unreadable The encryption key changed or was lost Not recoverable from a database backup. Restore the original key
No emails at all Mail settings wrong, or the mail path blocked Test from the application host. This locks users out silently
Uploads never process Queue-backed jobs enabled with the queue unreachable Check the queue. No error appears in the interface
Provider calls fail after working Credentials rotated, endpoint changed, or egress address changed Run the connection test; check the egress address the provider sees
Write-back stops after a burst of failures The circuit breaker opened Expected protective behaviour. Fix the endpoint; delivery resumes after cooldown
Dead-lettered events disappeared before investigation Dead-letter retention shorter than reaction time Raise it. Evidence purged before anyone looks is evidence lost
Verification data is stale Cache window longer than the business needs Shorten the relevant window, accepting the extra provider cost
Environments diverge Configuration drift Compare files between environments regularly