# Implementing a custom payment provider

## 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&#x20;

The background service is used to set up the definition for the provider on startup. You should be able to follow the guide for [Bootstrapping data on startup](https://dev.ucommerce.net/readme/how-to/entities-from-code/bootstrapping-data-on-startup) using the *PaymentMethods Definitions* as the definition type:

```csharp
// 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:

```csharp
// 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:

```csharp
// 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`:

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

## The Request Model&#x20;

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.

```csharp
// 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:

```csharp
// 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.

{% hint style="info" %}
Refer to the payment provider's documentation to best determine how to handle various operations.
{% endhint %}

## The Middleware

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

```csharp
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:

```csharp
/// <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;
}
```

<pre class="language-csharp"><code class="lang-csharp"><strong>/// &#x3C;summary>
</strong>/// Tells the application builder to use Stripe with the given callbackUri.
/// &#x3C;/summary>
public static IPaymentApplicationBuilder UseStripe(this IPaymentApplicationBuilder builder, string processCallbackUri = "/Stripe/process/callback")
{
    builder.UseProvider&#x3C;StripeCheckoutCallbackRequest, StripeCheckoutCallbackMiddleware, StripeCheckoutPaymentProvider>(processCallbackUri);

    return builder;
}
</code></pre>

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