Service Fee In-App

Some of the card readers Commerce SDK supports do not have a display or pin pad. In order to receive required input from the cardholder for a service fee transaction, Commerce SDK will notify the Integrator's POS system through API callbacks. The following information is required:

  1. Service Fee Confirmation: The POS system can send one of the following decisions to Commerce SDK based on the customer's input:
    • Accept: accept the service fee and send the transaction for authorization
    • Decline: decline the service fee and cancel the transaction
  2. Cardholder's Zip Code: Commerce SDK will only ask for cardholder's zip code if it wasn't already provided when the transaction was started.

The following card readers require Service Fee In-App:

  • Moby 5500
  • Roam RP457c

The following documents the API changes for different platforms:

CWS

When service fee confirmation is needed from the POS application, CWS sets property requiredInformation to either "RequireServiceFeePercentageConfirmation" (for percentage based service fee) or "RequireServiceFeeAmountConfirmation" (for fixed amount service fee) in the response to getPaymentTransactionStatus. CWS also sets property extraChargeLookupOutcome with the service fee details.

Response (Percentage Based):

{
    "requestId": "1895323070",
    "statusDetails": "REQUEST_ACCEPTED",
    "data": {
        "paymentGatewayCommand": {
            "completed": false,
            "eventQueue": [{
                "timeStamp": "1621608143104",
                "statusDetails": "SERVICE_FEE_LOOKUP_NEEDED"
            }, {
                "timeStamp": "1621608149770",
                "statusDetails": "SERVICE_FEE_LOOKUP_COMPLETED"
            }, {
                "timeStamp": "1621608149770",
                "statusDetails": "SERVICE_FEE_CONFIRMATION_STARTED"
            }],
            "chanId": "adb04d9c-56b8-4e8f-a623-706c01f46723",
            "requiredInformation": ["RequireServiceFeePercentageConfirmation"],
            "extraChargeLookupOutcome": {
                "allowExtraCharge": true,
                "extraChargeType": "SERVICE_FEE_P",
                "extraChargePercent": 3.0,
                "extraChargeAmount": {
                    "currencyCode": "USD",
                    "amount": 30
                },
                "totalAmount": {
                    "currencyCode": "USD",
                    "amount": 1030
                },
                "baseAmount": {
                    "currencyCode": "USD",
                    "amount": 1000
                },
                "extraChargeConfirmationOption": null
            }
        }
    }
}

Response (Fixed Amount):

{
    "requestId": "32878540",
    "statusDetails": "REQUEST_ACCEPTED",
    "data": {
        "paymentGatewayCommand": {
            "completed": false,
            "eventQueue": [{
                "timeStamp": "1621544840801",
                "statusDetails": "SERVICE_FEE_LOOKUP_NEEDED"
            }, {
                "timeStamp": "1621544840836",
                "statusDetails": "SERVICE_FEE_LOOKUP_COMPLETED"
            }, {
                "timeStamp": "1621544840836",
                "statusDetails": "SERVICE_FEE_CONFIRMATION_STARTED"
            }],
            "chanId": "a472114d-93ca-4944-99a2-31d0eb2e3e4a",
            "requiredInformation": ["RequireServiceFeeAmountConfirmation"],
            "extraChargeLookupOutcome": {
                "allowExtraCharge": true,
                "extraChargeType": "SERVICE_FEE_A",
                "extraChargePercent": 0.0,
                "extraChargeAmount": {
                    "currencyCode": "USD",
                    "amount": 100
                },
                "totalAmount": {
                    "currencyCode": "USD",
                    "amount": 1100
                },
                "baseAmount": {
                    "currencyCode": "USD",
                    "amount": 1000
                },
                "extraChargeConfirmationOption": null
            }
        }
    }
}

After getting service fee decision from the cardholder, integrating POS system can make continuePaymentTransaction request with decision Accept or Decline. If Decline is set or the field is empty, the transaction will be canceled.

Request (Percentage Based):

{
    "method": "continuePaymentTransaction",
    "requestId": "1895323071",
    "targetType": "paymentGatewayConverge",
    "version": "1.0",
    "parameters": {
        "RequireServiceFeePercentageConfirmation" : "Accept",
        "paymentGatewayId": "5728b0d8-1250-4955-bb62-b94cae6aef22",
        "chanId": "adb04d9c-56b8-4e8f-a623-706c01f46723"
    }
}

Request (Fixed Amount):

{
    "method": "continuePaymentTransaction",
    "requestId": "32878541",
    "targetType": "paymentGatewayConverge",
    "version": "1.0",
    "parameters": {
        "RequireServiceFeeAmountConfirmation": "Accept",
        "paymentGatewayId": "5728b0d8-1250-4955-bb62-b94cae6aef22",
        "chanId": "a472114d-93ca-4944-99a2-31d0eb2e3e4a"
    }
}

If service fee is accepted and zip code was not previously provided in the initial startPaymentTransaction request, CWS will set requiredInformation to "RequireAvsZipCode" in the response to getPaymentTransactionStatus.

Response:

{
    "requestId": "32878542",
    "statusDetails": "REQUEST_ACCEPTED",
    "data": {
        "paymentGatewayCommand": {
            "completed": false,
            "eventQueue": [],
            "chanId": "a472114d-93ca-4944-99a2-31d0eb2e3e4a",
            "requiredInformation": ["RequireAvsZipCode"]
        }
    }
}

After getting the zip code from the cardholder, integrating POS system can make continuePaymentTransaction request to provide the zip code to Commerce SDK. If zip code is not provided in the continuePaymentTransaction request, CWS will continue to set requiredInformation to "RequireAvsZipCode" in the response for getPaymentTransactionStatus until the zip code is provided.

Request:

{
    "method": "continuePaymentTransaction",
    "requestId": "32878543",
    "targetType": "paymentGatewayConverge",
    "version": "1.0",
    "parameters": {
        "RequireAvsZipCode": "30076",
        "paymentGatewayId": "5728b0d8-1250-4955-bb62-b94cae6aef22",
        "chanId": "a472114d-93ca-4944-99a2-31d0eb2e3e4a"
    }
}

Java

// Method transactionRequiresExtraChargeConfirmation is introduced to abstract class ECLTransactionProcessingListener
// CSDK will ask integrating POS system to perform service fee confirmation through this method.
@Override
public void transactionRequiresExtraChargeConfirmation(ECLTransactionInterface transaction,
                                                       ECLTenderInterface tender,
                                                       ECLExtraChargeLookupOutcome extraChargeLookupOutcome,
                                                       ECLTransactionProcessingCallbackListener transactionProcessingCallbackListener)
{
    // Integrating POS system sends the service fee decision back through interface transactionProcessingCallbackListener from the above method.
    // The first three parameters are the same ones from the above method,
    // and the last one is the decision. Allowed values for the last parameter are
    // ECLExtraChargeDecision.ACCEPT : consumer accepts service fee,
    // ECLExtraChargeDecision.DECLINE: consumer declines the service fee and cancels the ongoing transaction.
    transactionProcessingCallbackListener.setExtraChargeDecision(transaction, tender, extraChargeLookupOutcome, ECLExtraChargeDecision.ACCEPT);
}

// Method requireAvsFieldInformation is introduced to abstract class ECLTransactionProcessingListener
// CSDK will ask integrating POS system to provide the cardholder's zip code through this method if it was not provided in the initial processTransaction call.
@Override
public void requireAvsFieldInformation(ECLTransactionInterface transaction,
                                       ECLTenderInterface tender,
                                       ECLAVSField avsField,
                                       ECLTransactionProcessingCallbackListener transactionProcessingCallbackListener)
{
    if (eclAvsField == ECLAVSField.CARDHOLDER_ZIP)
    {
        String cardholderZip = "30076"; // replace with cardholder's zip code
        transactionProcessingCallbackListener.setAvsFieldContent(transaction, tender, avsField, cardholderZip);
    }
    else
    {
        // handle other AVS fields; not applicable for service fee
    }
}

Objective-C (iOS)

// Implementation of [ECLTransactionProcessingDelegate shouldProvideExtraChargeDecision:tender:extraChargeLookupOutcome:]
// CSDK will ask integrating POS system to perform service fee confirmation through this method.
- (void)shouldProvideExtraChargeDecision:(id<ECLCurrencyTransactionProtocol>)transaction tender:(id<ECLTenderProtocol>)tender extraChargeLookupOutcome:(ECLExtraChargeLookupOutcome *)extraChargeLookupOutcome {
    // set decision to ECLExtraChargeDecisionAccept; it can also be set to ECLExtraChargeDecisionDecline
    transaction.extraChargeDecision = ECLExtraChargeDecisionAccept;
    dispatch_async(dispatch_get_main_queue(), ^() {
        // use dispatch_async and call continueProcessingTransaction using your account reference (see sample app for more details)
        [[_account transactionProcessor] continueProcessingTransaction:transaction using:tender delegate:self];
    });
}

// Implementation of [ECLTransactionProcessingDelegate shouldProvideAvsFieldInformation:tender:avsField:]
// CSDK will ask integrating POS system to provide the cardholder's zip code through this method if it was not provided in the initial processTransaction call.
- (void)shouldProvideAvsFieldInformation:(id<ECLTransactionProtocol>)transaction tender:(id<ECLTenderProtocol>)tender avsField:(ECLAVSField)avsField {
    if (avsField == ECLAVS_CardholderZip) {
        NSString *cardholderZip = @"30076"; // replace with cardholder's zip code
        [tender setAVSField:avsField withValue:cardholderZip];
        dispatch_async(dispatch_get_main_queue(), ^() {
            // use dispatch_async and call continueProcessingTransaction using your account reference (see sample app for more details)
            [[_account transactionProcessor] continueProcessingTransaction:transaction using:tender delegate:self];
        });
    } else {
        // handle other AVS fields; not applicable for service fee
    }
}

C#

// Assume a CWS object cws is created and we have a delegate MyPaymentComplete to receive transaction update.
cws.StartPaymentTransaction(bea, MyNotifyCWSEvent, MyPaymentComplete);

// The following code demonstrates how to handle service fee confirmation and zip code
public void MyPaymentComplete(PaymentTransactionResults paymentResults)
{
    // get required information
    String[] req = paymentResults.GetRequiredInformation();
    if (null != req)
    {
        Dictionary<string, string> info = new Dictionary<string, string>();
        for (int i = 0; i < req.Length; i++)
        {
            if (String.Compare(req[i], "RequireServiceFeePercentageConfirmation", true) == 0)
            {
                info["RequireServiceFeePercentageConfirmation"] = "Accept"; // can also set to "Decline"
            }
            else if (String.Compare(req[i], "RequireServiceFeeAmountConfirmation", true) == 0)
            {
                info["RequireServiceFeeAmountConfirmation"] = "Accept"; // can also set to "Decline"
            }
            else if (String.Compare(req[i], "RequireAvsZipCode", true) == 0)
            {
                info["RequireAvsZipCode"] = "30076"; // replace with cardholder's zip code
            }
        }

        if (info.Count != 0)
        {
            // Continue the transaction
            cws.StartContinuePaymentTransaction(m_PaymentGatewayId, chanId, info, MyNotifyCWSEvent, MyPaymentComplete);
        }
    }
}