Custom Commission Merchant Example

A money-out payment merchant is essential to pay commissions. Although there are many providers built into the Platform, you have the power to add a custom one using the Client Extension.



Building a Custom Commission Merchant Integration

Full Example

public class CustomHyperWalletMoneyOutMerchant : AccountCommissionMerchant
{
  private const string ACCOUNT_NUMBER_KEY = "ActNum";
  public CustomHyperWalletMoneyOutMerchant() : base( 
    new MerchantInfo(9001, "CustomHyperWallet", "USD"), 
    new List<CommissionMerchantCustomField>
    {
      new CommissionMerchantCustomField
      {
        DisplayText = "Account Number",
        Key = ACCOUNT_NUMBER_KEY,
        IsRequired = true
        }
    }){}  
  
public override CommissionPaymentResults PayCommissions(int batchId, List<CommissionPayment> payments)
{
  var results = new List<CommissionPaymentResult>();            
  foreach (var payment in payments)
  {
    // Be careful here!
    // We process the whole batch at once, so you have to provide the error handling so the statuses are correctly saved.
    // If half of the payments succeeded, but then an exception was thrown, Disco would not receive the CommissionPaymentResults
    // and would be unaware that any of the payments went out. Try - catch handling is necessary
    try
    {
      if (payment.MerchantCustomFields.TryGetValue(ACCOUNT_NUMBER_KEY, out string accountNumber))
      {
        // call out to merchant to process payment                        
        results.Add(new CommissionPaymentResult()
                    {
                      // This one is important that you manually set this equal to the payment you just processed
                      PaymentUniqueId = payment.PaymentUniqueId, 
                      TransactionNumber = payment.PaymentUniqueId,
                      Status = CommissionPaymentStatus.Paid,
                      DatePaid = DateTime.Now,
                      CheckNumber = 100,
                    });
      }
      else
      {
        results.Add(new CommissionPaymentResult()
                    {
                      // This one is important that you manually set this equal to the payment you just processed
                      PaymentUniqueId = payment.PaymentUniqueId, 
                      Status = CommissionPaymentStatus.Failed,
                      ErrorMessage = "Account not initialized"
                      });
      }
    }
    catch (Exception e)
    {
      results.Add(new CommissionPaymentResult()
                  {
                    // This one is important that you manually set this equal to the payment you just processed
                    PaymentUniqueId = payment.PaymentUniqueId,
                    Status = CommissionPaymentStatus.Failed,
                    ErrorMessage = $"Exception ocurred while paying {payment.AssociateId} : {e.Message}"
                    }) ;
    }
  }            
  return new CommissionPaymentResults
  {
    Results = results
    };
} 

public override CommissionMerchantAccountFields ProvisionAccount(int associateID)
{
  // Create an account for this Associate and any other custom values you need in PayCommissions
  return new CommissionMerchantAccountFields
  {
    CustomValues = new Dictionary<string, string>
    {
      { ACCOUNT_NUMBER_KEY, "Response account number" }
    }
  };
}

Let's break this example down into sections to explain what's going on.

1. Declare new commission merchant class

In your Client Extension, under the Merchant directory, create a new CS file. Then define a class for your customer merchant. In this example, we're using Hyperwallet.

public class CustomHyperWalletMoneyOutMerchant : AccountCommissionMerchant

This new class inherits from AccountCommissionMerchant, a class you can extend to create a new custom money-out merchant implementation. Use AccountCommissionMerchant if an account for the Associate is created with the specified merchant.

2. Enter the merchant account number

In your class, define a constant variable string with the account number key provided by the merchant:

public class CustomHyperWalletMoneyOutMerchant : AccountCommissionMerchant
{
  private const string ACCOUNT_NUMBER_KEY = "ActNum";

3. Define a method with the merchant info

public CustomHyperWalletMoneyOutMerchant() : base( 
    new MerchantInfo(9001, "CustomHyperWallet", "USD"), 
    new List<CommissionMerchantCustomField>
    {
      new CommissionMerchantCustomField
      {
        DisplayText = "Account Number",
        Key = ACCOUNT_NUMBER_KEY,
        IsRequired = true
        }
    }){} 

MerchantInfo is a helper constructor to fill in the merchant properties, such as:

  • Merchant ID - Enter a number greater than 9000 to not conflict with standard merchant IDs
  • Display Name "CustomHyperWallet"
  • Currency code "USD"

Use CommissionMerchantCustomField to define information for this merchant to process payments. For example, an Associate might have a specific account number or access token created before payments can be made. These values are usually defined when the Associate selects this merchant to receive their payments and are then passed into the custom merchant when the payment is processed.

  • DisplayText - This is shown to the user to prompt them to enter the correct information.
  • Key - The primary identifier for this field; this will be the key in MerchantCustomFields when processing the payment.
  • IsRequired - Boolean. These are the fields required for the merchant to process the payment.

4. Declare class for payment batch results

public override CommissionPaymentResults PayCommissions(int batchId, List<CommissionPayment> payments)
{
  var results = new List<CommissionPaymentResult>();  

Use PayCommissions to define the custom logic to integrate with a merchant and process commission payments. It usually processes complete batches together.

We declare a variable called results as the CommissionPaymentResult, which are the results from processing a payment batch.

5. Loop through the payment batch

❗Warning!

Be careful here! We process the whole batch at once, so you have to provide the error handling so the statuses are correctly saved. If half of the payments succeeded, but then an exception was thrown, Disco would not receive the CommissionPaymentResults and would be unaware that any of the payments went out. Try - catch handling is necessary.

foreach (var payment in payments)
  {
    try
    {
      if (payment.MerchantCustomFields.TryGetValue(ACCOUNT_NUMBER_KEY, out string accountNumber))
      {                    
        results.Add(new CommissionPaymentResult()
                    {
                      PaymentUniqueId = payment.PaymentUniqueId, 
                      TransactionNumber = payment.PaymentUniqueId,
                      Status = CommissionPaymentStatus.Paid,
                      DatePaid = DateTime.Now,
                      CheckNumber = 100,
                    });
      }
      else
      {
        results.Add(new CommissionPaymentResult()
                    {
                      PaymentUniqueId = payment.PaymentUniqueId, 
                      Status = CommissionPaymentStatus.Failed,
                      ErrorMessage = "Account not initialized"
                      });
      }
    }
    catch (Exception e)
    {
      results.Add(new CommissionPaymentResult()
                  {
                    PaymentUniqueId = payment.PaymentUniqueId,
                    Status = CommissionPaymentStatus.Failed,
                    ErrorMessage = $"Exception ocurred while paying {payment.AssociateId} : {e.Message}"
                    }) ;
    }
}

Let's break this down a little:

try
    {
      if (payment.MerchantCustomFields.TryGetValue(ACCOUNT_NUMBER_KEY, out string accountNumber))
      {                       
        results.Add(new CommissionPaymentResult()

TryGetValue is a call out to the merchant to process payment.

PaymentUniqueId = payment.PaymentUniqueId,

It is essential that you manually set PaymentUniqueId equal to the payment you just processed.

6. Return results

  return new CommissionPaymentResults
  {
    Results = results
    };
} 

7, Provision a new merchant account

Create an account for this Associate and any other custom values you need in PayCommissions.

public override CommissionMerchantAccountFields ProvisionAccount(int associateID)
{
  return new CommissionMerchantAccountFields
  {
    CustomValues = new Dictionary<string, string>
    {
      { ACCOUNT_NUMBER_KEY, "Response account number" }
    }
  };
}