Skip to content

Environment Variables ​

See repository root .env.example. For the packaged production stack, copy deploy/pay/.env.example to .env; deploy/pay/docker-restart.sh refuses to start while any CHANGE_ME value remains.

VariableDescription
POSTGRES_DBDatabase name
POSTGRES_USERDatabase user
POSTGRES_PASSWORDDatabase password
REDIS_PASSWORDRedis Stack password used by local compose stacks; dev-only value belongs in local env files, never use a production secret in git
ConnectionStrings__RedisRedis connection string for runtime invite/session state (local dev host: localhost:6379; password is supplied via Redis__Password)
Redis__ConfigurationOptional Redis connection string override; when unset, ConnectionStrings__Redis is used
Redis__PasswordRedis password override for the API; in local compose it must match REDIS_PASSWORD
Redis__DatabaseOptional Redis logical database number for runtime stores and index initializers
Redis__AbortConnectOptional StackExchange.Redis abort-connect flag; default false for resilient startup
JWT_SIGNING_KEYJWT signing key (min 32 chars in prod)
LOG_DIRECTORYDirectory for Serilog rolling files (api-YYYYMMDD.log, api-errors-…, gateway-…). Default when unset: backend/logs. Prefer absolute path in production. See docs/docs/backend/logging.md.
LOG_ARCHIVE_DIROptional archive directory for rotated logs; default {LOG_DIRECTORY}/archive
ASPNETCORE_ENVIRONMENTUse Development to enable Debug Pay layers and Verbose IikoConnector (Serilog Trace).
PaySecrets__EncryptionKeyRequired when storing local Pay-managed secrets such as Syrve connection passwords; 32-byte AES key as base64, 64-char hex, or 32-byte UTF-8 value; never commit production keys
PaySecrets__KeyIdOptional key identifier stored with encrypted local secret records; default local-v1
SEED_ADMIN_EMAILDev seed admin email
SEED_ADMIN_PASSWORDDev seed admin password
BankFiles__RootPathControlled server-side root directory for temporary original bank file storage; default data/bank-files; never expose this path through API responses
BankFiles__RetentionHoursOriginal bank file retention in hours; default 24 for MHPAY-61
BankFiles__Cleanup__EnabledEnables the background original bank file retention cleanup worker; default true
BankFiles__Cleanup__IntervalSecondsBackground original bank file retention cleanup interval in seconds; default 300
VITE_API_BASE_URLFrontend API base (empty in prod same-origin)
VITE_DOCS_URLDocumentation portal URL
CORS__ALLOWEDORIGINS__0Allowed CORS origin(s)

Platform operational settings (env bootstrap) ​

Env defaults apply when the PlatformSettings DB row is empty or a field is null. DB overrides are managed via /api/platform/settings and /settings UI. Secrets (JWT, Postgres, seed admin, Syrve passwords) are not part of this layer.

VariableDefaultDescription
Platform__BankStatementUploadEnabledtrueDefault allow bank statement upload before org quota
Platform__MatchingDateToleranceDays14Matching date tolerance (falls back to Syrve__Matching__DateToleranceDays when unset in DB)
Platform__MatchingExactAmountTolerance0.01Matching amount tolerance (falls back to Syrve__Matching__ExactAmountTolerance when unset in DB)

Telegram bank-statement inbox ​

VariableDefaultDescription
Telegram__EnabledfalseFeature flag for Telegram inbox (link + webhook/polling + upload)
Telegram__BotUsernameemptyBot username without @ (for deep links)
Telegram__BotTokenemptyBotFather token; required when Enabled=true; never commit
Telegram__WebhookSecretemptyMust match setWebhook secret_token; required when Enabled and not UsePolling
Telegram__UsePollingfalseLong polling via getUpdates (local tuna only). On a public host set false so the API registers setWebhook
Telegram__NotifyOnRecognitiontruePush recognition/parse summaries to linked chat
Telegram__AllowPostFromBotfalseAllow PaymentRun approve from bot callbacks
Telegram__PublicAppBaseUrlhttp://localhost:5000SPA origin for deep links; do not append /api (trailing /api is stripped)
Telegram__ChallengeTtlMinutes10One-time personal link code TTL
Telegram__WebhookPublicUrlunsetPublic webhook URL; default {PublicAppBaseUrl}/api/telegram/webhook. Duplicate /api/api/ is collapsed

Operational settings still resolve as env defaults → platform DB → organization quota → location override (future) for supported settings. Legacy Syrve/iiko capability columns in platform/quota tables are deprecated and ignored; they do not disable registered Pay-host runtime capabilities.

Syrve orchestration ​

VariableDefaultDescription
Syrve__PostingMaxRetryAttempts5Max posting retries
Syrve__PostingRetryBaseDelaySeconds60Base retry delay
Syrve__Reconciliation__ReadbackRetryDelaysSeconds__05First readback retry delay (seconds)
Syrve__Reconciliation__ReadbackRetryDelaysSeconds__130Second readback retry delay
Syrve__Reconciliation__ReadbackRetryDelaysSeconds__2120Third readback retry delay
Syrve__Reconciliation__ReadbackRetryDelaysSeconds__3300Fourth readback retry delay
Syrve__Reconciliation__EscalateAfterAttempts4Create anomaly after this many failed reconciliation attempts
Syrve__DocumentSync__IntervalSeconds300Sync interval
Syrve__DocumentSync__LookbackDays90Document lookback window
Syrve__DocumentSync__MaxBatchSize100Global maximum documents per sync run across all configured document types
Syrve__DocumentSync__MaxConcurrentDocumentFetches4Maximum parallel per-document reads in bounded fallback/hybrid enrichment
Syrve__DocumentSync__OutgoingUnpaidRefreshMinutes60Reuse a fresh unchanged Outgoing snapshot for normal UI/worker sync; expired/modified/missing snapshots and explicit forceRefresh=true perform exact bounded unpaid reads
Syrve__DocumentSync__FetchDocumentDetailstruePersist full document/line details from unpaid batch; fallback calls document.getDocument only when local metadata/details are missing
Syrve__DocumentSync__PreferUnpaidBatchtrueTry getUnpaidInvoicesByDepartments first; unusable/failed responses automatically fall back without mass Paid transitions
Syrve__DocumentSync__EmptyBatchActiveListThreshold0Maximum active list size for accepting an empty batch without prior positive batch evidence or outstanding snapshots
Syrve__DocumentSync__UnpaidBatchDepartmentChunkSizeunsetOptional department chunk size for unpaid batch requests; each chunk is capped by the connector request limit
Syrve__DocumentSync__UnpaidBatchDepartmentIds__0unsetOptional first department UUID for CHAIN batch chunking; add indexed values as needed
Syrve__SupplierSync__IntervalSeconds3600Supplier sync interval
Syrve__SupplierSync__MaxBatchSize1000Local supplier apply batch; not sent to iiko and not network pagination
Syrve__SupplierSync__StaleAfterHours24Mark suppliers inactive when missing from sync
Syrve__Matching__DebitDocumentTypes__0IncomingInvoiceDocument types for bank debits
Syrve__Matching__DebitDocumentTypes__1ServiceReceiptAdditional debit types
Syrve__Matching__CreditDocumentTypes__0OutgoingInvoiceDocument types for bank credits
Syrve__Matching__CreditDocumentTypes__1ServiceProvisionAdditional credit types
Syrve__Matching__DateToleranceDays14Candidate date proximity window
Syrve__Matching__ExactAmountTolerance0.01Amount equality tolerance

Always-on Pay-host runtime ​

Capabilities registered by AddIikoConnectorForPayHost() are always enabled: live reads, document/supplier sync, and the worker-only payment posting path do not have env/config capability switches. New postings always start in ApprovalRequired; only POST /api/syrve/postings/{id}/approve can release them to worker execution.

The following removed keys must not be added to deployment profiles: Syrve__UseIikoConnector, Syrve__RuntimeCallsEnabled, Syrve__PaymentWriteEnabled, Syrve__PaymentWriteRequiresApproval, Syrve__AutoQueuePostingOnConfirm, Syrve__AllowTestEnvironmentWrites, Syrve__AllowProductionWrites, Syrve__DocumentSync__Enabled, Syrve__SupplierSync__Enabled, Iiko__RuntimeApiCallsEnabled, verification Enabled/VerificationStatus/ContractVerificationStatus, and verification bypass flags.

Read-only smoke is an operator procedure: do not create/approve a posting. It is not implemented by disabling runtime capabilities.

New/updated Syrve connection passwords entered through Pay are stored in SecretRecords as AES-GCM encrypted local secrets and referenced from SyrveConnections.PasswordSecretRef as pay-secret:{secretRecordId}. The API never returns raw passwords or secret references in SyrveConnectionDto.

Deployment-managed secrets remain supported: set PasswordSecretRef=env:YOUR_VAR directly in the database/deployment path when the password is managed outside Pay, and define YOUR_VAR in the process environment. Legacy secret:VAR aliases are normalized to env:VAR.

Iiko runtime on Pay API host ​

Pay uses the minimal AddIikoConnectorForPayHost subset. Deployment must preserve transport endpoint/method configuration from repository appsettings.json when replacing the Iiko section, but no runtime/verification status or bypass flag is required.

Before every approved write, Pay still enforces scoped RBAC, manual approval, idempotency, payable/amount/allocation/anomaly checks, server applicability, credentials, HTTP/RPC and method-specific preflight, plus retry/payload/response limits. Generic RPC failures are interpreted by the method-specific preflight policy; there is no deployment bypass.

Optional operator-provided test targets:

env
IIKO_TEST_PAYMENT_ACCOUNT_FROM=<guid>
TEST_SYRVE_CASHFLOW_ARTICLE_ID=<guid>

Warning: Always-on capability is not authorization. Never approve a production posting without the owner-approved production procedure and all safety checks.

Never commit real secrets.

Mistral document recognition ​

Environment variable.NET keyDefault / rule
MISTRAL_API_KEYMistral__ApiKeySecret; required only when enabled.
MISTRAL_ENABLEDMistral__Enabledfalse.
MISTRAL_BASE_URLMistral__BaseUrlhttps://api.mistral.ai; HTTPS is required in Production.
MISTRAL_OCR_MODELMistral__OcrModelmistral-ocr-latest; required when enabled.
MISTRAL_TIMEOUT_SECONDSMistral__TimeoutSeconds180, positive.
MISTRAL_MAX_RETRIESMistral__MaxRetries3, non-negative.
MISTRAL_DELETE_REMOTE_FILESMistral__DeleteRemoteFilestrue.
MISTRAL_REMOTE_FILE_EXPIRY_SECONDSMistral__RemoteFileExpirySeconds3600, positive.
MISTRAL_INCLUDE_BLOCKSMistral__IncludeBlockstrue; required for source anchoring.
MISTRAL_CONFIDENCE_GRANULARITYMistral__ConfidenceGranularityword; word/page.
MISTRAL_TABLE_FORMATMistral__TableFormatmarkdown; markdown/html.
RECOGNITION_WORKER_ENABLEDRecognitionWorker__Enabledtrue.
RECOGNITION_WORKER_POLL_INTERVAL_SECONDSRecognitionWorker__PollIntervalSeconds5.
RECOGNITION_WORKER_LEASE_SECONDSRecognitionWorker__LeaseSeconds300.
RECOGNITION_WORKER_BATCH_SIZERecognitionWorker__BatchSize5.
RECOGNITION_LEARNING_ENABLEDRecognitionLearning__Enabledtrue.
RECOGNITION_LEARNING_REQUIRE_MANUAL_APPROVALRecognitionLearning__RequireManualApprovaltrue.
RECOGNITION_LEARNING_MINIMUM_APPROVED_EXAMPLESRecognitionLearning__MinimumApprovedExamples500.
RECOGNITION_LEARNING_MINIMUM_EXAMPLES_PER_BANKRecognitionLearning__MinimumExamplesPerBank50.
RECOGNITION_LEARNING_DATASET_BUILD_INTERVAL_HOURSRecognitionLearning__DatasetBuildIntervalHours168.
RECOGNITION_LEARNING_CANARY_PERCENTRecognitionLearning__CanaryPercent5.
BankFiles__RecognitionReviewRetentionHourssame168.

Startup validation allows a missing key/model only while disabled. Health checks make no paid request. The key is runtime environment configuration only: never a build arg, image layer, appsettings value, database value, API/browser value or log field.