Working with Challenges

Challenges are potential issues the Clover device may encounter while attempting to process a Payment. A Challenge is triggered by a potential duplicate Payment (DUPLICATE_CHALLENGE) or an offline Payment (OFFLINE_CHALLENGE).

When a Challenge is raised, the Clover device calls the ICloverConnectorListener.OnConfirmPaymentRequest() method and passes in a ConfirmPaymentRequest object that contains the Payment and the list of Challenges it encountered. In response, the merchant must either accept the Payment (and any risk associated with it), or reject the Payment. Until the Payment is accepted or rejected, the Clover device will remain on the “Merchant is verifying your payment” screen.

Handling offline Challenges

An OFFLINE_CHALLENGE is raised when the Clover device attempts to process a card transaction while the device is not connected to the network. The Clover device is unable to verify with the payment gateway that the card is both valid and has sufficient funds.

To accommodate the higher risk associated with an offline transaction, we present you and the merchant with an OFFLINE_CHALLENGE to let you decide whether or not you would like to accept or reject the transaction.

There are three common ways to handle offline challenges:

  • Accept all payments processed offline, with the merchant assuming the associated risk.
  • Reject all payments processed offline, minimizing the merchant’s risk at the expense of potentially missing revenue.
  • Have the POS indicate that the card transaction occurred offline, and state the risk associated with accepting the payment. This option should present two buttons for accepting and rejecting the payment.

If the merchant chooses to accept the payment, Clover will add the payment request to the device’s offline queue, and send it to the payment gateway when the device regains network connectivity.

Handling duplicate Payment Challenges

Duplicate Payment Challenges are raised when multiple Payments are made with the same card type and last four digits within the same hour.

Important

For this reason, we recommend that you do not programmatically call CloverConnector.RejectPayment() on all instances of DUPLICATE_CHALLENGE.

To avoid false positives for DUPLICATE_CHALLENGE, we suggest that you either:

  1. Implement your own logic that also compares the Payment amount
  2. Generate a pop-up message that asks the merchant if the Payment is a duplicate

Comparing Payment amounts

You can determine whether a DUPLICATE_CHALLENGE was triggered by an actual duplicate Payment request (rather than a different Payment made with the same card type and last four digits within the same hour) by comparing the Payment amount to the amount from the previous transaction. The following code snippet demonstrates how to implement this logic for Remote Pay Windows.

//1. Make a sale.
//2. Save the SaleResponse from OnSaleResponse(SaleResponse)
//3. Call cloverConnector.RetrievePayment(RetrievePaymentResponse)

OnRetrievePaymentResponse(RetrievePaymentResponse response) 
{
    if (response.Success)
    {
        uiThread.Send(delegate (object state)
        {
            String details = "No matching payment";
            Payment payment = response.Payment;
            if (payment != null)
            {
                if(payment.amount == lastSalesResponse.Payment.amount)
                {
                    details = "Created:" + dateFormat(payment.createdTime) + "\nResult: " + payment.result
               + "\nPaymentId: " + payment.id + "\nOrderId: " + payment.order.id
                + "\nAmount: " + currencyFormat(payment.amount) + " Tip: " + currencyFormat(payment.tipAmount) + " Tax: " + currencyFormat(payment.taxAmount);
                }
            }
            AlertForm.Show(this, response.QueryStatus.ToString(), details);
        }, null);
    }
    else if (response.Result.Equals(ResponseCode.FAIL))
    {
        uiThread.Send(delegate (object state)
        {
            AlertForm.Show(this, response.Reason, response.Message);
        }, null);
    }
    else if (response.Result.Equals(ResponseCode.CANCEL))
    {
        uiThread.Send(delegate (object state)
        {
            AlertForm.Show(this, response.Reason, response.Message);
        }, null);
    }
}

Requesting merchant verification

Alternatively, you can ask the merchant to verify whether the Payment is a duplicate.

bool lastChallenge = false;
for (int i = 0; i < request.Challenges.Count; i++)
{
    uiThread.Send(delegate (object state)
    {
        if (i == request.Challenges.Count - 1) // if this is the last challenge
        {
            lastChallenge = true;
        }
        Challenge challenge = request.Challenges[i];
        ConfirmPaymentForm confirmForm = new ConfirmPaymentForm(parentForm, challenge, lastChallenge);
        confirmForm.FormClosed += (object s, FormClosedEventArgs ce) =>
        {
            if (confirmForm.Status == DialogResult.No)
            {
                cloverConnector.RejectPayment(request.Payment, challenge);
                i = request.Challenges.Count;
            }
            else if (confirmForm.Status == DialogResult.OK) // Last challenge was accepted
            {
                cloverConnector.AcceptPayment(request.Payment);
            }
            confirmPaymentFormBusy.Set(); //release the confirmPaymentFormBusy WaitOne lock
        };
        confirmForm.Show();
    }, null);
    confirmPaymentFormBusy.WaitOne(); //wait here until Accept or Reject pressed
}

Accepting and rejecting Payments

You can accept a Payment by calling CloverConnector.AcceptPayment(Payment), using the Payment obtained from ConfirmPaymentRequest.Payment. The snippet below shows how to do this with Remote Pay Windows.

cloverConnector.AcceptPayment(request.Payment);

To reject the Payment and prevent it from proceeding, call CloverConnector.RejectPayment(Payment, Challenge) using the Payment obtained from ConfirmPaymentRequest.Payment and the Challenge obtained from ConfirmPaymentRequest.Challenges.

cloverConnector.RejectPayment(request.Payment, request.Challenges[i]);

If you have further questions, please visit the Clover Developer Community, or contact us at semi-integrations@clover.com.