using QuestionsApi.Models; using Stripe; using Stripe.Checkout; namespace QuestionsApi.Services; public interface IStripeAccessGateway { Task CreateCheckoutAsync(AccessPurchase purchase, AccessProduct product, CancellationToken cancellationToken); } public sealed class StripeAccessGateway(IConfiguration configuration) : IStripeAccessGateway { public async Task CreateCheckoutAsync( AccessPurchase purchase, AccessProduct product, CancellationToken cancellationToken) { var secretKey = configuration["Stripe:SecretKey"]; if (string.IsNullOrWhiteSpace(secretKey)) throw new InvalidOperationException("Stripe secret key is not configured."); var successUrl = configuration["Stripe:AccessSuccessUrl"] ?? "https://doctor.ranaze.com/donation-complete.html?session_id={CHECKOUT_SESSION_ID}"; var cancelUrl = configuration["Stripe:AccessCancelUrl"] ?? "https://doctor.ranaze.com/donation-canceled.html"; var metadata = new Dictionary { ["access_purchase_id"] = purchase.Id ?? "", ["access_sku"] = product.Sku, ["user_id"] = purchase.UserId }; var service = new SessionService(new StripeClient(secretKey)); var session = await service.CreateAsync(new SessionCreateOptions { Mode = "payment", SuccessUrl = successUrl, CancelUrl = cancelUrl, ClientReferenceId = purchase.Id, CustomerCreation = "always", BillingAddressCollection = "auto", AutomaticTax = new SessionAutomaticTaxOptions { Enabled = true }, Metadata = metadata, PaymentIntentData = new SessionPaymentIntentDataOptions { Metadata = metadata }, LineItems = [ new SessionLineItemOptions { Quantity = 1, PriceData = new SessionLineItemPriceDataOptions { Currency = product.Currency, UnitAmount = product.AmountCents, ProductData = new SessionLineItemPriceDataProductDataOptions { Name = product.Name, Description = "A manually activated RanaZe access entitlement." } } } ] }, null, cancellationToken); if (string.IsNullOrWhiteSpace(session.Id) || string.IsNullOrWhiteSpace(session.Url)) throw new InvalidOperationException("Stripe did not return a checkout URL."); return new StripeCheckoutResult(session.Id, session.Url); } }