Open-Source Wikis

/

Bitwarden Server

/

Apps

/

Billing

bitwarden/server

Billing

Active contributors: billing team.

Purpose

src/Billing/ is a small, focused HTTP service whose only job is to receive webhooks from the third-party payment providers Bitwarden integrates with, validate them, and apply the resulting state changes to the database. It does not contain any user-facing UI; that lives in the Api (self-service) and Admin (operations) apps. The heavy lifting (subscription creation, plan changes, proration, license generation) lives in src/Core/Billing/ services.

Directory layout

src/Billing/
├── Program.cs / Startup.cs
├── Controllers/
│   ├── StripeController.cs        # /stripe/webhook (subscription, invoice, payment_method, customer.* events)
│   ├── PayPalController.cs        # /paypal/ipn (Instant Payment Notification)
│   ├── BitPayController.cs        # /bitpay/ipn (BitPay/crypto)
│   ├── AppleController.cs         # /apple/iap-webhook (Apple App Store server notifications)
│   ├── RecoveryController.cs      # /recovery/* (admin re-process of dropped webhook events)
│   └── InfoController.cs          # /alive, /version
├── Services/
│   ├── StripeEventService.cs        # Translates Stripe webhook events → domain calls
│   ├── StripeFacade.cs              # Thin Stripe SDK adapter
│   ├── StripeEventProcessor.cs      # Dedupes / processes events by id
│   ├── StripeWebhookUtility.cs
│   └── ...
├── Constants/                      # Stripe event-name constants, log-context keys
├── Jobs/                           # AliveJob, retry jobs
├── Models/                         # Webhook payload DTOs
├── BillingSettings.cs              # Strongly-typed config (ApiKey, WebhookKeys, FreshDesk, Onboarding)
├── appsettings.{Development,Production,QA}.json
└── Dockerfile / build.sh / entrypoint.sh

Key abstractions

Type Path Description
Startup src/Billing/Startup.cs Registers Stripe SDK, mail, repos, identity auth, billing services + Quartz jobs.
StripeController src/Billing/Controllers/StripeController.cs Validates the Stripe-Signature header against globalSettings.Stripe.WebhookKeys, then dispatches to IStripeEventProcessor.
IStripeEventService / StripeEventService src/Billing/Services/ Maps Stripe events (customer.subscription.updated, invoice.created, customer.discount.deleted, …) to domain operations like IUserService.AdjustStorageAsync or ISubscriberService.UpdateSubscription.
PayPalController src/Billing/Controllers/PayPalController.cs Verifies PayPal IPN signatures, then routes to IPaymentService.HandleIpn.
BitPayController src/Billing/Controllers/BitPayController.cs Crypto-payment notifications.
AppleController src/Billing/Controllers/AppleController.cs App Store Server Notifications V2 (mobile premium upgrades).
RecoveryController src/Billing/Controllers/RecoveryController.cs Operator endpoint to re-fire missed Stripe events.
Domain services in src/Core/Billing/Services/ Where the actual business logic lives — ProviderBillingService, OrganizationBillingService, IPriceIncreaseScheduler, etc.

How it works

sequenceDiagram
    participant Stripe
    participant Billing as Billing app
    participant Core as Core domain
    participant DB

    Stripe->>Billing: POST /stripe/webhook (signed)
    Billing->>Billing: Verify Stripe-Signature
    Billing->>Core: IStripeEventProcessor.ProcessAsync(event)
    Core->>DB: Update Subscription / Invoice / TaxRate / Transaction
    Core->>DB: IEventService.LogOrganizationEventAsync
    Billing-->>Stripe: 200 OK

The pattern repeats per provider — each controller verifies the provider-specific signature, deduplicates by event id, and calls into src/Core/Billing/. Idempotency is achieved by writing event IDs to a BillingEventLog style table.

Long-running work in 2025-2026

A long-running Stripe price-migration project landed throughout 2025-2026 (IPriceIncreaseScheduler — PR #7305, 2026-03-26; schedule-aware storage commands — PR #7350; cancel/reinstate path migration — PR #7331, 2026-03-31). The general direction is to replace ad-hoc proration calculations with Stripe-native subscription schedules, gated by feature flags so the cloud rollout is reversible.

Integration points

  • Stripe — primary payment provider. The Stripe SDK is configured in Startup.cs with StripeConfiguration.ApiKey = globalSettings.Stripe.ApiKey.
  • Database — same shared repositories as Api (src/Infrastructure.Dapper / src/Infrastructure.EntityFramework).
  • MailIMailService for receipt emails on certain events.
  • Event logIEventService.LogOrganizationEventAsync for org-scope billing events visible in audit logs.
  • Admin — re-fires events via RecoveryController if a webhook was missed or processing failed.

Self-host

Self-hosted instances do not subscribe via Stripe; their billing flows go through the licensing API on the cloud. The Billing host is therefore unused on self-host (the bundled stack does not start it).

Entry points for modification

  • New Stripe event type → add a constant in src/Billing/Constants/StripeEvents.cs and a handler in IStripeEventService / StripeEventService.
  • New payment provider → add a controller with signature verification, define a new IXxxEventService, and register it in Startup.cs.
  • New domain logic for an existing event → modify the appropriate src/Core/Billing/Services/...Service.cs. Don't add domain logic in the controller layer.
  • New scheduled billing job → register it in JobsHostedService (src/Billing/Jobs/).

For the broader picture see features/billing-and-subscriptions.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Billing – Bitwarden Server wiki | Factory