In commercial SaaS platforms, Billing & Subscriptions is a mission-critical subsystem with zero tolerance for financial discrepancies:
- Concurrency Quota Breaches: When multiple requests arrive concurrently demanding quota (e.g. AI tokens or storage), lack of atomic locking leads to negative balances and severe revenue leakage;
- Webhook Retries & Out-of-Order Delivery: Payment gateways retry webhooks upon transient timeouts; handlers must enforce strict idempotency to prevent duplicate credit top-ups;
- Subscription Lifecycle Finite State Machine: Managing transitions across Trial, Active, Dunning, Grace Period, and Suspended states.
BitzOrcas.Modern Billing Module builds an enterprise financial shield via “Atomic Mutexes + Strict State Machines + Idempotent Outbox Events”:
Subscription Lifecycle and Payment Fulfillment
Step 1: Subscription Aggregate Root and Lifecycle
using System;using System.ComponentModel;using BitzOrcas.Domain.Entities;using BitzOrcas.Domain.Results;using BitzOrcas.Persistence.Metadata;
namespace BitzOrcas.Billing.Domain;
public static class SubscriptionErrors{ public static readonly Error InvalidState = Error.Conflict("Billing.InvalidState", "Subscription cannot be activated from current state.");
public static readonly Error NotFound = Error.NotFound("Billing.SubscriptionNotFound", "Subscription not found.");}
[BitzTable("BilSubscription", IsTenant = true, IsSoftDelete = true, Description = "Tenant Subscriptions Table")]public sealed class SubscriptionAggregate : TenantAggregateRoot<string>{ [BitzColumn(Length = 64, IsRequired = true)] public string PlanCode { get; private set; } = string.Empty;
[BitzColumn(IsRequired = true)] public SubscriptionStatus Status { get; private set; } = SubscriptionStatus.PendingPayment;
// Subscription time window [BitzColumn(IsRequired = true)] public DateTimeOffset StartsAt { get; private set; }
[BitzColumn(IsRequired = true)] public DateTimeOffset ExpiresAt { get; private set; }
[Obsolete("For ORM materialization only. Use Create.", error: true)] [EditorBrowsable(EditorBrowsableState.Never)] public SubscriptionAggregate() : base("0") { }
// State machine transition activating subscription upon payment public Result Activate(string transactionId, DateTimeOffset now) { if (Status == SubscriptionStatus.Active) { // Idempotency: already active returns success immediately return Result.Success(); }
if (Status != SubscriptionStatus.PendingPayment) { return Result.Failure(SubscriptionErrors.InvalidState); }
// State machine transition Status = SubscriptionStatus.Active; StartsAt = now; ExpiresAt = now.AddMonths(1);
AddDomainEvent(new SubscriptionActivatedDomainEvent(Id, TenantId, PlanCode, ExpiresAt, transactionId)); return Result.Success(); }}Step 2: Idempotent Payment Webhook Fulfillment
using System.Threading;using System.Threading.Tasks;using BitzOrcas.Application.Abstractions.Idempotency;using BitzOrcas.Domain.Abstractions;using BitzOrcas.Domain.Results;
public sealed class ProcessPaymentWebhookCommandHandler( ICommandRepository<SubscriptionAggregate, string> subscriptionRepo, IIdempotencyStore idempotencyStore, IAppClock clock){ public async ValueTask<Result> Handle(ProcessPaymentWebhookCommand command, CancellationToken ct) { // 1. Acquire distributed lock on external transaction ID var lockKey = $"payment:webhook:{command.TransactionId}"; var acquired = await idempotencyStore.TryAcquireAsync(lockKey, ct); if (!acquired.Acquired) { // Replay protection: return success on duplicate webhooks return Result.Success(); }
// 2. Retrieve target subscription aggregate var subscriptionResult = await subscriptionRepo.FindAsync(command.SubscriptionId, ct); if (subscriptionResult.IsFailure) { return Result.Failure(SubscriptionErrors.NotFound); }
var subscription = subscriptionResult.Value;
// 3. Execute domain state transition var activateResult = subscription.Activate(command.TransactionId, clock.UtcNow); if (activateResult.IsFailure) return activateResult;
// 4. Save aggregate (auto-committed by TransactionPipeline) await subscriptionRepo.UpdateAsync(subscription, ct);
return Result.Success(); }}Summary
The Billing Module secures commercial revenue:
- Zero Loss Prevention: Distributed mutexes + optimistic locking safeguard quota reservations;
- End-to-End Idempotency: Payment webhooks and invoice generators are 100% idempotent;
- Event-Driven Entitlements: Activated subscriptions immediately broadcast events, refreshing tenant feature quotas in milliseconds.