Payment and Invoice Processing Using Stripe in .NET

Introduction

Stripe is one of the online and in-person payment processing systems. Its not open source. In below sample, we are using test version. We can do operations like create a customer, charge, invoices, refund, webook, etc.

In the below sample, I have used the Stripe.net package for Stripe payment processing in dotnet and Stripe REST API's.

The Card Tokenization with Angular 15 and various payment-related functionalities using tokens generated by Card tokenization will be covered in the upcoming article.

In this article, we will look at an operation.

  1. Stripe Account Setup
  2. Creation of Customer
  3. Payment method and payment intent
  4. Invoices and invoice line items
  5. Charge
  6. Refund

Stripe Account Setup

To begin using Stripe for payment integration, the first step is to create a Stripe account.

  • Step 1. Navigate to Stripe register.
  • Step 2. Fill out the required fields, such as email, full name, and password, country.
  • Step 3. After creating your account, Stripe will ask you for some business details (or personal details if you're using it as an individual) to complete the setup.

Stripe operates in both test mode and live mode. In test mode, you can simulate transactions without actually charging cards. Once everything is working as expected, you can switch to live mode to begin processing real payments.

Note. Stripe uses test mode by default. You can toggle to live mode from the dashboard once you're ready.

Customer

Install a stripe.net package from nuget manager to our project.

Nuget package

Create Customer

The customer is the main object which will hold multiple payment methods, invoices, and billing info. we can create customer for individual or business organization.

Code Sample

// Configures the Stripe SDK with the secret key for API communication
private void ConfigureStripe()
{
    // Retrieve the secret key from the configuration settings
    string? stripeSecretKey = _configuration.GetValue<string>("SecretKey");

    // Check if the secret key is null or empty; throw an exception if validation fails
    if (string.IsNullOrEmpty(stripeSecretKey))
    {
        throw new Exception("Stripe secret key is null or empty");
    }

    // Set the Stripe secret key to the SDK's global configuration
    StripeConfiguration.ApiKey = stripeSecretKey;
}

// Creates a new customer in the Stripe system using provided customer details
public Customer CreateCustomer(StripeCustomerRequest stripeCustomerRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a Stripe customer
        var options = new CustomerCreateOptions
        {
            Email = stripeCustomerRequest.Email,        // Customer's email address
            Name = stripeCustomerRequest.Name,          // Customer's full name
            Phone = stripeCustomerRequest.Phone,        // Customer's phone number
            Description = stripeCustomerRequest.Description // Description for the customer (e.g., reason for account creation)
        };

        // Instantiate the CustomerService to interact with Stripe's Customer API
        var service = new CustomerService();

        // Create and return the new customer by making an API call to Stripe
        return service.Create(options);
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create customer", ex);
    }
}

Create customers with tokenization

Creates a new customer in the Stripe system, associating a payment source; basically, it will create a customer after getting card info from users.

Code Sample

// Creates a new customer in the Stripe system, associating a payment source (e.g., tokenized card)
public Customer CreateCustomerWithToken(StripeCustomerRequest stripeCustomerRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a Stripe customer with a payment source
        var options = new CustomerCreateOptions
        {
            Email = stripeCustomerRequest.Email,                 // Customer's email address
            Name = stripeCustomerRequest.Name,                   // Customer's full name
            Phone = stripeCustomerRequest.Phone,                 // Customer's phone number
            Description = stripeCustomerRequest.Description,     // Description for the customer
            Source = stripeCustomerRequest.SourceID              // Token representing a payment source (e.g., card details)
        };

        // Instantiate the CustomerService to interact with Stripe's Customer API
        var service = new CustomerService();

        // Create and return the new customer by making an API call to Stripe
        return service.Create(options);
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create customer with token", ex);
    }
}

Update Customer

We can update existing customers using customer ID. We can update the info like email, phone, description, source ID, etc.

Code Sample

// Updates an existing customer in the Stripe system with the provided customer details.
public Customer UpdateCustomer(StripeCustomerRequest stripeCustomerRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Create an instance of CustomerUpdateOptions to define the fields to update
        var options = new CustomerUpdateOptions
        {
            Email = stripeCustomerRequest.Email,        // Update customer's email address
            Name = stripeCustomerRequest.Name,          // Update customer's full name
            Phone = stripeCustomerRequest.Phone,        // Update customer's phone number
            Description = stripeCustomerRequest.Description // Update description (e.g., reason for the update)
        };

        // If SourceID is provided, add it to the options to update the payment method (e.g., a new token)
        if (!string.IsNullOrEmpty(stripeCustomerRequest.SourceID))
        {
            options.Source = stripeCustomerRequest.SourceID; // Update the payment source for the customer
        }

        // Instantiate the CustomerService to interact with Stripe's Customer API
        var service = new CustomerService();

        // Update the customer by calling the Update method with the customer ID and the update options
        return service.Update(stripeCustomerRequest.CustomerID, options);
    }
    catch (StripeException ex)
    {
        // Log the Stripe exception error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to update customer", ex);
    }
}

Stripe Customer Request Class

public class StripeCustomerRequest
{
    public string Email { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string CustomerID { get; set; }
    public string Description { get; set; }
    public string SourceID { get; set; }
}

Payment Method

A payment method is a way that customers pay for a product or service. In a brick-and-mortar store, accepted payment methods may include cash, a gift card, credit cards, prepaid cards, debit cards, or mobile payments.

Stripe will support various cards, debit, wallets, real-time transfers, bank transfers, etc.

In this sample, we are using a credit card as a payment method.

Create payment method

Code Sample

// Creates a new payment method (credit card) in Stripe
public PaymentMethod CreatePaymentMethod(CreatePaymentMethodRequest createPaymentMethodRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a payment method (credit card)
        var paymentMethodOptions = new PaymentMethodCreateOptions
        {
            Type = "card", // Specifies that the payment method is a credit card
            Card = new PaymentMethodCardOptions
            {
                Number = createPaymentMethodRequest.Number,    // Card number
                ExpMonth = createPaymentMethodRequest.ExpMonth, // Expiration month
                ExpYear = createPaymentMethodRequest.ExpYear,   // Expiration year
                Cvc = createPaymentMethodRequest.Cvc            // Card security code (CVC)
            }
        };

        // Instantiate the PaymentMethodService to interact with Stripe's API
        var paymentMethodService = new PaymentMethodService();

        // Create the payment method by calling the Create method from the service
        PaymentMethod paymentMethod = paymentMethodService.Create(paymentMethodOptions);

        // Return the created payment method
        return paymentMethod;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create payment method", ex);
    }
}

// Request class for creating a payment method
public class CreatePaymentMethodRequest
{
    public string Number { get; set; }
    public string Cvc { get; set; }
    public int ExpMonth { get; set; }
    public int ExpYear { get; set; }
}

Attach Payment Method

Move the payment method to the customer.

code sample

// Attaches an existing payment method to a customer
public bool AttachPaymentMethod(AttachPaymentMethodRequest attachPaymentMethodRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for attaching the payment method to the customer
        var attachOptions = new PaymentMethodAttachOptions
        {
            Customer = attachPaymentMethodRequest.CustomerId // The ID of the customer to attach the payment method to
        };

        // Instantiate the PaymentMethodService to interact with Stripe's API
        var paymentMethodService = new PaymentMethodService();

        // Attach the payment method to the customer
        paymentMethodService.Attach(attachPaymentMethodRequest.PaymentMethodId, attachOptions);

        // Return true if the attachment is successful
        return true;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to attach payment method", ex);
    }
}

// Class representing the request for attaching a payment method
public class AttachPaymentMethodRequest
{
    public string CustomerId { get; set; }
    public string PaymentMethodId { get; set; }
}

Delete payment method

Remove the payment method from the customer using the Stripe customer ID and payment method ID.

Code sample

// Deletes (detaches) a payment method from a customer
public async Task<PaymentMethod?> DeleteCard(string customerId, string cardId)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();
        // Instantiate the PaymentMethodService to interact with Stripe's API
        var service = new PaymentMethodService();
        // Detach the payment method (card) from the customer using the card ID
        var paymentMethod = await service.DetachAsync(cardId);
        // Return the detached payment method
        return paymentMethod;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to delete payment method", ex);
    }
}

Payment Intent

The PaymentInten defines how the customer wants to pay for the service or business, and has details about the transaction, such as the supported payment methods, the amount to collect, and the desired currency.

Create Payment Intent with a Payment Method

Code Sample

// Creates a PaymentIntent for a specific payment
public PaymentIntent CreatePaymentIntent(CreatePaymentIntentRequest createPaymentIntentRequest)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a payment intent
        var paymentIntentOptions = new PaymentIntentCreateOptions
        {
            Amount = createPaymentIntentRequest.Amount * 100, // Convert the amount to cents (Stripe expects the amount in the smallest currency unit)
            Currency = "usd", // Specify the currency for the payment
            Customer = createPaymentIntentRequest.CustomerId, // The Stripe customer ID associated with the payment
            PaymentMethod = createPaymentIntentRequest.PaymentMethodId, // The payment method to be used
            PaymentMethodTypes = new List<string> { "card" }, // Type of payment method (e.g., "card")
            OffSession = createPaymentIntentRequest.OffSession, // Indicates if the payment is happening off-session (e.g., without user interaction)
            Confirm = true // Automatically confirms the payment when created
        };

        // Instantiate the PaymentIntentService to interact with Stripe's API
        var paymentIntentService = new PaymentIntentService();

        // Create the payment intent using the defined options
        PaymentIntent paymentIntent = paymentIntentService.Create(paymentIntentOptions);

        // Return the created payment intent
        return paymentIntent;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create payment intent", ex);
    }
}

// Request class for creating a PaymentIntent
public class CreatePaymentIntentRequest
{
    public string CustomerId { get; set; }
    public string PaymentMethodId { get; set; }
    public long Amount { get; set; } // Amount in cents
    public bool OffSession { get; set; } // Set true if charging without customer present (e.g., subscription)
}

Create payment intent without a payment method

It's like a direct one-time payment.

Code Sample

// Creates a PaymentIntent without specifying a payment method upfront (automatic payment methods enabled)
public Task<PaymentIntent> CreatePaymentIntentWithOutPaymentMethod(PaymentRequest request)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Define the options for creating a payment intent without a specified payment method
        var options = new PaymentIntentCreateOptions
        {
            Amount = request.Amount * 100, // Convert the amount to cents (Stripe expects the amount in the smallest currency unit)
            Currency = "usd", // Specify the currency for the payment
            AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
            {
                Enabled = true, // Automatically enable supported payment methods (e.g., card)
            },
        };

        // Instantiate the PaymentIntentService to interact with Stripe's API
        var service = new PaymentIntentService();

        // Asynchronously create the payment intent using the defined options
        var paymentIntent = service.CreateAsync(options);

        // Return the task of the payment intent creation
        return paymentIntent;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and the original exception as the inner exception
        throw new Exception("Failed to create payment intent", ex);
    }
}

Invoices

Invoices hold detailed information about the service provided, the due amount collected from the customer, and the customer's payment method.

Generate Invoice

// Generates and sends an invoice for a customer in Stripe
public Stripe.Invoice? GenerateInvoice(Invoice invoice)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Create invoice item options to specify the product/service being invoiced
        var invoiceItemOptions = new InvoiceItemCreateOptions
        {
            Customer = invoice.CustomerId.ToString(), // Customer ID for the invoice
            Amount = invoice.TotalAmount, // Total amount to be invoiced (in cents)
            Currency = "usd", // Currency for the invoice
            Description = "Product or Service Description", // Description of the product/service
        };

        // Create the invoice item (add a line item to the invoice)
        var invoiceItemService = new InvoiceItemService();
        var invoiceItem = invoiceItemService.Create(invoiceItemOptions); // This creates the invoice item

        // Define invoice options to create the actual invoice for the customer
        var invoiceOptions = new InvoiceCreateOptions
        {
            Customer = invoice.CustomerId, // Customer ID for the invoice
            AutoAdvance = true // Automatically finalize and send the invoice when it's created
        };

        // Create the invoice
        var invoiceService = new InvoiceService();
        var invoice1 = invoiceService.Create(invoiceOptions); // Create the invoice

        // Finalize the invoice (making it ready for payment)
        invoiceService.FinalizeInvoice(invoice1.Id);

        // Send the invoice to the customer
        var sendInvoiceOptions = new InvoiceSendOptions();
        invoiceService.SendInvoice(invoice1.Id, sendInvoiceOptions);

        // Return the generated invoice
        return invoice1;
    }
    catch (StripeException ex)
    {
        // Log the error message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and include the original exception for further debugging
        throw new Exception("Failed to generate invoice", ex);
    }
}

public class Invoice
{
    public int InvoiceId { get; set; }
    public DateTime InvoiceDate { get; set; }
    public string CustomerId { get; set; }
    public long TotalAmount { get; set; }
    public List<InvoiceLineItem> LineItems { get; set; }
}

public class InvoiceLineItem
{
    public int InvoiceLineItemId { get; set; }
    public int InvoiceId { get; set; }
    public string Description { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public decimal LineTotal => Quantity * UnitPrice;
    public Invoice Invoice { get; set; }
}

Pay Invoice

Customers can pay the invoice later, with the preferred payment method.

// Pays an invoice using a specified payment method
public Stripe.Invoice? PayInvoice(string paymentMethodID, string invoiceID)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Initialize the InvoiceService to interact with Stripe's invoice system
        var invoiceService = new InvoiceService();

        // Create options for paying the invoice, including the payment method ID
        var payInvoiceOptions = new InvoicePayOptions
        {
            PaymentMethod = paymentMethodID,  // Payment method ID (obtained from the customer or frontend)
        };

        // Attempt to pay the invoice using the provided payment method
        var paidInvoice = invoiceService.Pay(invoiceID, payInvoiceOptions);

        // Return the paid invoice object
        return paidInvoice;
    }
    catch (StripeException ex)
    {
        // Log the Stripe exception message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and include the original exception for further debugging
        throw new Exception("Failed to pay invoice", ex);
    }
}

Refund Customer

Refund plays a key role in the payment processing system; we can refund the amount when the amount was deducted wrong.

// Processes a refund for a specific charge made by a customer
public Stripe.Refund? Refund(string customerID, long amount)
{
    try
    {
        // Ensure Stripe is properly configured with the secret key
        ConfigureStripe();

        // Initialize the RefundService to interact with Stripe's refund system
        var refunds = new RefundService();

        // Create options for the refund, including the amount and the charge ID
        var options = new RefundCreateOptions
        {
            Amount = amount,  // The amount to refund (in cents, e.g., $50.00 is 5000)
            Charge = customerID // The ID of the charge to refund (associated with the customer)
        };

        // Attempt to create the refund using the provided options
        var payment = refunds.Create(options);

        // Return the refund object containing the details of the refund
        return payment;
    }
    catch (StripeException ex)
    {
        // Log the Stripe exception message for debugging purposes
        Console.WriteLine($"Stripe Exception: {ex.StripeError.Message}");

        // Throw a new exception with a custom message and include the original exception for further debugging
        throw new Exception("Failed to refund amount", ex);
    }
}

Conclusion

This approach enables the creation of a robust payment system integrated with Stripe, giving you the ability to scale and manage payments efficiently within your application.

Attached is the sample code.


Similar Articles