Configuration Reference
All PolarSharp settings live under the PolarSharp key in appsettings.json. Every setting shown here is optional except AccessToken.
Full appsettings.json example
{
"PolarSharp": {
"Mode": "Test",
"AccessToken": "tok_sandbox_xxx",
"CustomBaseUrl": null,
"BasePath": "/v1",
"ApiVersion": null,
"ApiVersionStrictness": "Warn",
"TimeoutMs": 30000,
"MaxRetries": 3,
"Resilience": {
"CircuitBreakerFailureThreshold": 5,
"CircuitBreakerSamplingSeconds": 30,
"CircuitBreakerBreakSeconds": 15,
"HedgeAfterMs": null
},
"Connection": {
"MaxConnectionsPerServer": 100,
"PooledConnectionLifetimeMinutes": 15,
"PooledConnectionIdleTimeoutMinutes": 2,
"EnableHttp2": true,
"EnableHttp3": false,
"EnableMultipleHttp2Connections": true
},
"Webhooks": {
"Secret": "whsec_xxx",
"Path": "/hooks/polar",
"RequireHttps": true,
"ToleranceSeconds": 300
}
}
}
Core settings
| Key | Type | Default | Description |
|---|---|---|---|
Mode |
"Test" | "Live" | "Custom" |
"Test" |
Target environment. "Test" uses Polar's sandbox — no real charges. "Live" uses production — real transactions. |
AccessToken |
string | (required) | Polar Organization Access Token. For sandbox: tok_sandbox_…. For production: tok_live_…. Keep in user-secrets or a secret manager. |
CustomBaseUrl |
string? | null |
Required when Mode = "Custom". Must be an absolute HTTPS URI. |
BasePath |
string | "/v1" |
URL path prefix for all requests. Changes rarely; only update when Polar releases /v2/. |
ApiVersion |
string? | SDK default | ISO date pinning the Polar API schema version sent as Polar-Version header. null = SDK's bundled version. See API Versioning. |
ApiVersionStrictness |
"Warn" | "Strict" | "Off" |
"Warn" |
What to do when ApiVersion differs from the SDK's bundled version. "Strict" fails startup. |
TimeoutMs |
int | 30000 |
Per-attempt HTTP timeout in milliseconds. Range: 1000–300000. |
MaxRetries |
int | 3 |
Maximum retry attempts. Range: 0–10. |
Resilience sub-options (PolarSharp:Resilience)
| Key | Default | Description |
|---|---|---|
CircuitBreakerFailureThreshold |
5 |
Number of consecutive failures before the circuit opens. |
CircuitBreakerSamplingSeconds |
30 |
Window in which failures are counted. |
CircuitBreakerBreakSeconds |
15 |
How long the circuit stays open before allowing probe requests. |
HedgeAfterMs |
null (disabled) |
If set, sends a duplicate GET/HEAD after this many ms to reduce tail latency. Never applied to mutating requests. |
Connection sub-options (PolarSharp:Connection)
| Key | Default | Description |
|---|---|---|
MaxConnectionsPerServer |
100 |
Caps simultaneous TCP connections to Polar per host. |
PooledConnectionLifetimeMinutes |
15 |
Forces TCP reconnection at this interval — refreshes DNS for cloud load balancer rotation. |
PooledConnectionIdleTimeoutMinutes |
2 |
Closes idle connections after this period to reclaim memory. |
EnableHttp2 |
true |
Use HTTP/2 multiplexing (one TCP connection for many concurrent requests). |
EnableHttp3 |
false |
Experimental QUIC/HTTP3 (opt-in; server support varies). |
EnableMultipleHttp2Connections |
true |
Allow multiple simultaneous HTTP/2 connections (increases parallelism under burst load). |
Webhook sub-options (PolarSharp:Webhooks)
Only used when AddPolarWebhooks() is called. See Webhooks.
| Key | Default | Description |
|---|---|---|
Secret |
null |
Shorthand for a single webhook secret (whsec_…). Treated as a one-element Secrets list. |
Secrets |
[] |
List of active webhook secrets. Supports zero-downtime rotation — verification passes if any secret matches. |
Path |
"/hooks/polar" |
Route that receives Polar webhook deliveries. |
RequireHttps |
true |
Reject non-HTTPS requests with 400 (not a redirect). |
ToleranceSeconds |
300 |
Maximum allowed age of a webhook timestamp before replay-protection rejects it. |
Startup validation
Missing AccessToken or invalid settings fail startup immediately with a clear error message, before any HTTP traffic is served. Set ASPNETCORE_ENVIRONMENT=Development to get the full exception detail.
Multi-tenant: single-tenant -> MT upgrade (PolarSharp:MultiTenant:SingleTenantUpgrade)
Bound by services.AddPolarSingleTenantUpgrade(configuration) from PolarSharp.MultiTenant.EntityFrameworkCore. Drives the one-time backfill that runs the first time a host that was previously running in single-tenant mode boots up with multi-tenant mode enabled.
| Key | Type | Default | Required | Validation / Notes |
|---|---|---|---|---|
EnableAutomaticUpgrade |
bool |
true |
optional | When true, the hosted service runs the upgrade on first MT-mode boot. Set false to invoke the upgrade explicitly via dotnet polar-mt upgrade during a chosen maintenance window. |
DefaultTenantStrategy |
enum | LiteralDefault |
optional | One of LiteralDefault (auto-create a single named tenant), FirstUserOrganization (resolve from the Identity package's user-to-org mapping), HostSupplied (delegate to an IDefaultTenantResolver the host registers). FirstUserOrganization throws NotSupportedException until the Identity package's MT integration ships. |
LiteralDefaultTenantSlug |
string |
"default" |
required when strategy is LiteralDefault |
Slug pattern: lowercase alphanumeric and hyphens, no leading or trailing hyphens, length 1–64. |
LiteralDefaultTenantName |
string |
"Default Tenant" |
required when strategy is LiteralDefault |
Display name for the auto-created tenant. |
RequireGracefulQuiescence |
bool |
true |
optional | Refuses to run unless the host has signalled quiescence. Set false only on low-traffic systems where briefly serving partially-stamped reads is acceptable. |
MaxRunDuration |
TimeSpan |
00:30:00 |
optional | Hard wall-clock cap. Hosts with very large single-tenant datasets (millions of rows across many tables) may need to increase. |
Consumed by PolarSharp.MultiTenant.EntityFrameworkCore (the hosted-service orchestration) and each provider-specific migrator package (PolarSharp.MultiTenant.EntityFrameworkCore.Sqlite, .SqlServer, .Postgres, .MariaDb, .CosmosDb).
Multi-tenant: SQLite Litestream replication (PolarSharp:MultiTenant:Sqlite:Litestream)
Bound by services.AddPolarSqliteLitestream(configuration) (called transitively by UseSqlite(...)). The entire section is gated by UseLitestream; with the toggle off, the validator is a no-op and every sub-field is ignored.
| Key | Type | Default | Required when UseLitestream=true |
Validation / Notes |
|---|---|---|---|---|
UseLitestream |
bool |
false |
n/a (the master toggle) | When false, no Litestream-related services run. |
ReplicaTargetType |
enum | S3 |
required | One of S3, AzureBlob, GoogleCloudStorage, Sftp, LocalDisk. The matching sub-options object must be populated. |
SyncIntervalSeconds |
int |
1 |
optional | Range [1, 3600]. How often Litestream flushes WAL changes to the replica. |
SnapshotIntervalMinutes |
int |
60 |
optional | Range [1, 1440]. Lower values speed point-in-time restores at the cost of more replica objects. |
RetentionDays |
int |
30 |
optional | Range [1, 365]. Affects the point-in-time restore window and replica storage cost. |
MetricsPort |
int |
9090 |
optional | Range [1024, 65535]. Litestream's Prometheus metrics endpoint port. |
HealthCheckEnabled |
bool |
true |
optional | When true, the PolarSharp health check pings /metrics and surfaces lag. |
HealthCheckMaxLagSeconds |
int |
30 |
optional | Range [1, 3600]. Threshold for Degraded vs. Healthy. |
AutoRegenerateOnTenantChange |
bool |
false |
optional | When true, the auto-regenerator IHostedService watches .db files + lifecycle notifications and signals Litestream via SIGHUP on POSIX. Windows hosts log a Warning instead. |
ConfigOutputPath |
string |
"/etc/litestream.yml" |
required when auto-regen enabled | Where the generator writes the YAML. Directory must be writable by the host process. |
LitestreamPidFilePath |
string |
"/var/run/litestream.pid" |
required when auto-regen enabled | Path to Litestream's PID file (Litestream must be started with --pidfile). |
AutoRegenerateDebounceWindow |
TimeSpan |
00:00:02 |
optional | Collapses bursts of file/lifecycle events into one regeneration. |
S3 sub-options (PolarSharp:MultiTenant:Sqlite:Litestream:S3)
Required when ReplicaTargetType = S3. Also covers MinIO / Backblaze B2 / Wasabi via EndpointUrl + ForcePathStyle.
| Key | Type | Default | Required | Notes |
|---|---|---|---|---|
Bucket |
string |
"" |
required | S3 bucket name. |
Region |
string |
"us-east-1" |
required | AWS region (or compatible store's region). |
PathPrefix |
string |
"polarsharp/tenants/" |
optional | Prefix prepended to every replicated .db file. |
AccessKeyIdEnvVar |
string |
"AWS_ACCESS_KEY_ID" |
required | Name of the env var. Never the value. |
SecretAccessKeyEnvVar |
string |
"AWS_SECRET_ACCESS_KEY" |
required | Name of the env var. Never the value. |
EndpointUrl |
string? |
null |
optional | Non-null for S3-compatible stores. |
ForcePathStyle |
bool |
false |
optional | Required for MinIO and some other S3-compatible stores. |
AzureBlob sub-options (PolarSharp:MultiTenant:Sqlite:Litestream:AzureBlob)
Required when ReplicaTargetType = AzureBlob.
| Key | Type | Default | Required | Notes |
|---|---|---|---|---|
AccountName |
string |
"" |
required | Azure Storage account name. |
Container |
string |
"polarsharp-tenants" |
required | Blob container name. |
PathPrefix |
string |
"" |
optional | Prefix prepended to every replicated .db file. |
AccessKeyEnvVar |
string |
"AZURE_STORAGE_KEY" |
required | Name of the env var holding the Storage account key. |
GoogleCloudStorage sub-options (PolarSharp:MultiTenant:Sqlite:Litestream:GoogleCloudStorage)
Required when ReplicaTargetType = GoogleCloudStorage.
| Key | Type | Default | Required | Notes |
|---|---|---|---|---|
Bucket |
string |
"" |
required | GCS bucket name. |
PathPrefix |
string |
"polarsharp/tenants/" |
optional | Prefix prepended to every replicated .db file. |
CredentialsJsonPath |
string |
"" |
required | Absolute filesystem path to a service-account JSON file. Validator confirms the file exists. |
Sftp sub-options (PolarSharp:MultiTenant:Sqlite:Litestream:Sftp)
Required when ReplicaTargetType = Sftp.
| Key | Type | Default | Required | Notes |
|---|---|---|---|---|
Host |
string |
"" |
required | SFTP host. |
Port |
int |
22 |
optional | SFTP port. |
User |
string |
"" |
required | SFTP login user. |
Path |
string |
"/srv/polarsharp/tenants/" |
required | Remote path on the SFTP host. |
PrivateKeyPath |
string |
"" |
required | Absolute filesystem path to the SSH private key. Validator confirms the file exists. |
LocalDisk sub-options (PolarSharp:MultiTenant:Sqlite:Litestream:LocalDisk)
Required when ReplicaTargetType = LocalDisk. Primarily for tests and development.
| Key | Type | Default | Required | Notes |
|---|---|---|---|---|
Path |
string |
"/var/lib/polarsharp/litestream-replica/" |
required | Local replica directory. Validator creates if absent. |
Credentials policy
All credentials are referenced by environment variable name, never embedded in appsettings. Supply the actual values via systemd EnvironmentFile=, Docker secrets, AWS Secrets Manager, or whatever the platform uses. The validator logs a Warning at startup if a referenced env var is unset but does NOT fail — secrets often arrive after process start through indirection.
Consumed by PolarSharp.MultiTenant.EntityFrameworkCore.Sqlite.
Multi-tenant: tenant lifecycle (PolarSharp:MultiTenant:TenantStatus)
Bound by services.AddPolarTenantLifecycle(configuration) from PolarSharp.MultiTenant. Configures the ITenantStatusService policy knobs that gate suspension and govern the soft-delete retention window.
| Key | Type | Default | Required | Validation / Notes |
|---|---|---|---|---|
RequireVerifiedEmailForSuspension |
bool |
true |
optional | When true, SuspendAsync refuses to suspend a tenant whose SiteManagerEmailVerified=false — the suspension notification would be unverifiable. Set false to globally relax. |
SuspendUnverifiedTenantsAnyway |
bool |
false |
optional | Per-call override that preserves the global RequireVerifiedEmailForSuspension requirement but bypasses on this specific call. Provided as a separate flag so the audit trail captures which form of relaxation was applied. |
DeletedTenantRetentionDays |
int |
90 |
optional | Retention period for soft-deleted tenants before a separate cleanup process (out of scope for ITenantStatusService) permanently removes the data. |
Consumed by PolarSharp.MultiTenant.
Multi-tenant: site-manager notifications (PolarSharp:MultiTenant:Notifications)
Bound by services.AddPolarMultiTenantNotifications(configuration) from PolarSharp.MultiTenant.Notifications. Opt-in at two levels: the host has to install the NuGet AND set Enabled = true.
| Key | Type | Default | Required | Validation / Notes |
|---|---|---|---|---|
Enabled |
bool |
false |
n/a (the master toggle) | When false, the registered MediatR handler runs but immediately returns — no validation cost, no outbound HTTP. |
EnabledChannels.Email |
bool |
true |
optional | Whether the email channel dispatches. |
EnabledChannels.Sms |
bool |
false |
optional | Whether the SMS channel dispatches. |
EnabledChannels.Webhook |
bool |
false |
optional | Whether the webhook channel dispatches. |
SendToUnverifiedEmail |
bool |
false |
optional | When false, the email channel skips recipients with SiteManagerEmailVerified=false. SMS + webhook are unaffected. |
Email sub-options (PolarSharp:MultiTenant:Notifications:Email)
| Key | Type | Default | Required when email channel enabled | Notes |
|---|---|---|---|---|
Provider |
enum | SendGrid |
required | Only SendGrid is supported in v1.0. |
FromAddress |
string |
"" |
required | The From: header on outgoing messages. |
FromDisplayName |
string |
"PolarSharp Platform" |
optional | Display name on the From: header. |
SendGrid.ApiKeyEnvVar |
string |
"SENDGRID_API_KEY" |
required | Name of the env var holding the SendGrid API key. |
Sms sub-options (PolarSharp:MultiTenant:Notifications:Sms)
| Key | Type | Default | Required when SMS channel enabled | Notes |
|---|---|---|---|---|
Provider |
enum | Twilio |
required | Only Twilio is supported in v1.0. |
Twilio.AccountSidEnvVar |
string |
"TWILIO_ACCOUNT_SID" |
required | Name of the env var. |
Twilio.AuthTokenEnvVar |
string |
"TWILIO_AUTH_TOKEN" |
required | Name of the env var. |
Twilio.FromNumber |
string |
"" |
required | Twilio-provisioned From: number in E.164 format (e.g., +15558675309). |
Webhook sub-options (PolarSharp:MultiTenant:Notifications:Webhook)
| Key | Type | Default | Required when webhook channel enabled | Notes |
|---|---|---|---|---|
Url |
string |
"" |
required | HTTPS URL the webhook POSTs the JSON payload to. |
SigningSecretEnvVar |
string |
"POLARSHARP_WEBHOOK_SECRET" |
required | Name of the env var holding the HMAC signing secret. Receiver verifies the X-PolarSharp-Signature: sha256={hex} header. |
TimeoutSeconds |
int |
10 |
optional | Range [1, 300]. |
Templates sub-options (PolarSharp:MultiTenant:Notifications:Templates)
One template object per status transition: Suspended, Reactivated, Deactivated, Deleted. Each carries EmailSubject, EmailBody, SmsBody (all support placeholder substitution: {TenantName}, {TenantIdentifier}, {NewStatus}, {PreviousStatus}, {Reason}, {OccurredAt}). Sensible defaults ship per transition; hosts can override any individual field.
Credentials policy
All channel credentials are referenced by environment variable name, never embedded in appsettings. The validator logs a Warning at startup if a referenced env var is unset but does NOT fail — secrets often arrive after process start through indirection.
Consumed by PolarSharp.MultiTenant.Notifications.