Ucommerce
  • Ucommerce Next Gen
    • Getting Started
      • Prerequisites
      • Licensing
      • Ucommerce Templates
      • Headless Template
      • MVC Template
    • Headless
      • Postman Collection
      • Headless API Authentication
        • Token endpoint - Authorization Header
        • Authorization Scopes
        • Refreshing the Access Token
      • Reference
        • Cart
        • Cart / Order Line Items
        • Shipment
        • Billing
        • Promotion Codes
        • Price Groups
        • Payment Methods
        • Countries
        • Shipping Methods
        • Catalogs
        • Cart Custom Properties
        • Line Item Custom Properties
        • Orders
        • Views for Cart modifying operations
      • Custom Headless APIs
      • Error Handling
      • Pagination
      • Deprecation
    • Backoffice Authentication
      • Microsoft Entra ID Example
      • Auth0 Authentication Example
    • Definitions
      • What is a Definition
    • Search and indexing
      • Configuration
      • Indexing
        • Index Definitions
        • Facets
        • Indexing Prices
        • Suggestions
        • Custom Data
      • Searching
    • Payment Providers
      • Stripe Provider Integration
      • Implementing a custom payment provider
    • Data Import
    • Miscellaneous
      • Media
      • Price Group Inheritance
      • Price Group Criteria
      • Soft Deletion Of Entities
      • Logging
      • OpenTelemetry
    • Extensions
      • Extending Pipelines
        • Order Processing Pipelines
        • Checkout Pipelines
      • Changing Service Behavior
        • Images
        • Content
      • Custom Headless APIs
      • Extend the Backoffice
        • Custom UI Components
      • Custom Editor UI
      • Custom Promotion Criteria
      • Custom Price Group Criteria
    • How-To
      • Migrate from Classic
        • Common database issues
      • Entities from code
        • Bootstrapping data on startup
        • Product Definitions & Fields
      • Discover pipelines and their tasks
      • Executing a pipeline
    • Integrations
      • Umbraco Media Delivery API
      • App Slices
        • Product Picker
  • Release Notes
  • Contact Us
Powered by GitBook
On this page
  • What you will need
  • The Background Service
  • The Request Model
  • The Payment Provider
  • The Middleware
  • Registration

Was this helpful?

  1. Ucommerce Next Gen
  2. Payment Providers

Implementing a custom payment provider

PreviousStripe Provider IntegrationNextData Import

Last updated 6 months ago

Was this helpful?

What you will need

To implement a payment provider, you will need to build the following:

  • A background service to set up the definition.

  • A request to model callbacks from the payment provider.

  • A payment provider class.

  • A middleware to process callbacks from the payment provider.

The Background Service

The background service is used to set up the definition for the provider on startup. You should be able to follow the guide for using the PaymentMethods Definitions as the definition type:

// Gets the definition type from the database
var definitionType = await dbContext.Set<DefinitionTypeEntity>()
                    .FirstOrDefaultAsync(x => x.Name == "PaymentMethod Definitions", token);

First, build up the definition field entities:

// Creates a list of definition field names and data types matching the 
// payment provider's needs
var fields = new List<KeyValuePair<string, string>>
{
    new("PublicKey", "ShortText"),
    new("SecretKey", "ShortText"),
    new("SuccessUrl", "ShortText"),
    new("CancelUrl", "ShortText"),
    new("WebhookSecret", "ShortText")
}.ToImmutableDictionary();
var definitionFields = new List<DefinitionFieldEntity>();
fields.ForEach(field => definitionFields.Add(new DefinitionFieldEntity
{
    BuiltIn = false,
    DataType = field.Value,
    Definition = definition,
    Multilingual = false,
    Name = field.Key,
    DisplayOnSite = true,
    RenderInEditor = true
}));

Then build the definition with the list of definition fields and the correct definition type, and add it to change tracking:

// Creates and tracks the definition
var definition = new DefinitionEntity
    {
        BuiltIn = false,
        Description = "Payment provider for X",
        Name = "X",
        DefinitionType = definitionType,
        DefinitionFields = definitionFields
    };
await dbContext.AddAsync(definition, token);

Finally, the background service should save using the dbContext:

// Saves via DbContext
await dbContext.SaveChangesAsync(token);

The Request Model

The request must inherit from CallbackRequestBase and pass the payment entity to the base class. It's also recommended that the request takes any objects the payment provider may send to the application, as parameters.

// Record that takes in payment, a Stripe Event, Stripe Signature and JSON
public record StripeCheckoutCallbackRequest(PaymentEntity Payment, Event StripeEvent, string StripeSignature, string Json) : CallbackRequestBase(Payment);

The Payment Provider

The provider must inherit from one of the payment provider base classes supported. Currently, there are 2 options:

  • RenderpagePaymentProvider This is for payment providers that render inside the storefront. This provider contains a GetForm method to render the payment form in the storefront.

  • RedirectionPaymentProvider This is for payment providers that redirect to a new page to complete the payment. This provider contains a GetRedirectUrl method, which can be used to redirect the customer to their payment.

Both types contain the following methods:

  • Cancel, to cancel an authorized payment.

  • Capture, to capture the payment when goods have been shipped.

  • ProcessCallback, to process the callback from the provider when the payment is created.

  • Refund, to refund a payment.

  • Alias, a string value that ties the definition and provider together. It must match the name of the definition created with the background service.

The payment provider wraps the callback request, so in this example, it will look like this:

// Payment provider class for stripe
public class StripeCheckoutPaymentProvider : RenderPagePaymentProvider<StripeCheckoutCallbackRequest>

Once the provider class is created, add the logic to handle the corresponding operation of each method as needed.

Refer to the payment provider's documentation to best determine how to handle various operations.

The Middleware

The middleware must inherit from ProcessCallbackMiddlewareBase<T>, where T is the request model, e.g.:

public class StripeCheckoutCallbackMiddleware : ProcessCallbackMiddlewareBase<StripeCheckoutCallbackRequest>

The base class contains 2 abstract methods you must implement:

  • ParseCallback

  • ValidateCallback

These methods will be run as the first step of the middleware and are used to ensure the validity of the callback and protect the system.

Registration

In order to encapsulate all logic related to the provider, and making it easy to reuse, it's recommended to create extension methods for the payment provider using the PaymentBuilder and IPaymentApplicationBuilder, here is an example of how such methods could look:

/// <summary>
/// Adds Stripe and all needed services to the application builder.
/// </summary>
public static PaymentBuilder AddStripe(this PaymentBuilder builder)
{
    builder.UcommerceBuilder.Services.AddHostedService<SetupStripeDefinitions>();
    builder.UcommerceBuilder.Services.AddScoped<IPaymentProvider, StripeCheckoutPaymentProvider>();
    builder.UcommerceBuilder.Services.AddUnique<IPaymentProvider<StripeCheckoutCallbackRequest>, StripeCheckoutPaymentProvider>(ServiceLifetime.Scoped);

    return builder;
}
/// <summary>
/// Tells the application builder to use Stripe with the given callbackUri.
/// </summary>
public static IPaymentApplicationBuilder UseStripe(this IPaymentApplicationBuilder builder, string processCallbackUri = "/Stripe/process/callback")
{
    builder.UseProvider<StripeCheckoutCallbackRequest, StripeCheckoutCallbackMiddleware, StripeCheckoutPaymentProvider>(processCallbackUri);

    return builder;
}

These methods can now be called on the PaymentBuilder and IPaymentApplicationBuilder on startup to register and use the provider.

Bootstrapping data on startup