Prerequisites: Authentication · Run a sale
A surcharge is an additional fee that we apply to card-present sales if surcharging is active on the terminal and if the card supports surcharging. When the SDK calculates a surcharge, it pauses the sale and asks your app to present the fee to the customer for confirmation.
If a card is eligible for surcharging, the following flow describes what happens during a sale:
- Your app runs a sale.
- The customer taps their card.
- Our gateway authorizes the transaction and calculates the surcharge.
- Your app presents the fee to the customer:
- If the customer accepts, your app confirms that our gateway should apply the surcharge. Our gateway sends the sale for settlement.
- If the customer declines, your app notifies the SDK, which then automatically reverses the sale.
- If the confirmation timer expires, the SDK automatically reverses the sale.
Integration steps
- Read your surcharge settings.
- Run a sale.
- Confirm the surcharge.
- Handle reversal errors
- (Optional) Change the confirmation timeout
Step 1. Read your surcharge settings
We configure surcharging on the terminal, so your app can't adjust the surcharge settings. Your app can only read the surcharge settings from CoreSettings.surchargeSettings in your onSettingsRetrieved: callback.
CoreSurchargeSettings has the following properties:
| Property | Type | Description |
|---|---|---|
enable | NSNumber* (bool) | true when surcharging is active for the terminal. |
allowBypass | NSNumber* (bool) | true when customers can opt out of the surcharge before they tap. |
discloseFee | NSNumber* (bool) | true when you must disclose the fee to the customer. |
percentage | NSNumber* | The surcharge rate as a percentage of the sale amount. |
Important: Don't hard-code the surcharge settings. Always read CoreSettings.surchargeSettings at runtime.
Step 2. Run a sale
Create a sale request, and set bypassSurcharge to false or nil.
Note: If you want to let the customer bypass the surcharge, set bypassSurcharge to true instead. The SDK then skips the confirmation step in Step 3 and completes the sale without applying the surcharge fee.
Swift
guard terminal.getDevice() != NODEVICE else {
// The reader isn't connected. Prompt the merchant to connect before you continue.
return
}
let sale = CoreSale()
sale.amount = 42.00
sale.transactionInputMethod = TAP
sale.orderId = "YOUR_ORDER_REFERENCE"
sale.bypassSurcharge = false
terminal.processSale(sale)
Objective-C
if ([[WTPSTerminal singleton] getDevice] == NODEVICE) {
// The reader isn't connected. Prompt the merchant to connect before you continue.
return;
}
CoreSale *sale = [[CoreSale alloc] init];
sale.amount = [NSNumber numberWithDouble:42.00];
sale.transactionInputMethod = TAP;
sale.orderId = @"YOUR_ORDER_REFERENCE";
sale.bypassSurcharge = [NSNumber numberWithBool:NO];
[[WTPSTerminal singleton] processSale:sale];
Step 3. Confirm the surcharge
When you run the sale and the cardholder taps their card, our gateway authorizes the sale and checks if the card is eligible for surcharging.
After our gateway authorizes the card, the SDK calls onRequestSurchargeConfirm: on your CoreAPISaleListener with a CoreBinLookupResponse that contains the calculated surcharge. Depending on whether the customer accepts or declines the surcharge, your app must respond by calling confirmSurchargeFee: with either true or false.
Important: If your app doesn't call confirmSurchargeFee: within the timeout window, the SDK automatically reverses the sale. The default timeout window is 30 seconds. To change the timeout window, go to Change the confirmation timeout.
Display the confirmation
Use the surcharge amount from binLookupResponse.surcharge.amount to create a screen that displays the surcharge amount to the customer and prompts them to accept or decline the surcharge. We recommend that you show any tips or taxes alongside the surcharge so that the customer sees the full total.
If the customer accepts
Call confirmSurchargeFee(true). The SDK keeps the sale as approved and calls onSaleResponse: with an approved response.
If the customer declines
Call confirmSurchargeFee(false). The SDK reverses the authorized sale. When the reversal completes, onSaleResponse: returns a declined response with a code of D and a status of VOID.
To handle a failed reversal, go to Handle reversal errors.
Example
The following example displays the surcharge amount to the customer and calls confirmSurchargeFee: with the response:
Swift
func onRequestSurchargeConfirm(_ binLookupResponse: CoreBinLookupResponse!) {
var message = String(
format: "Surcharge fee: %@\nConfirm?",
binLookupResponse.surcharge.amount
)
// Optionally include a tip and tax breakdown that you already calculated
if let breakdown = breakDownLabel.text {
message = breakdown + "\n" + message
}
showSurchargeAlert(message: message)
}
func showSurchargeAlert(message: String) {
let alert = UIAlertController(title: "Surcharge", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Accept", style: .default) { _ in
self.terminal.confirmSurchargeFee(true)
})
alert.addAction(UIAlertAction(title: "Decline", style: .destructive) { _ in
self.terminal.confirmSurchargeFee(false)
})
present(alert, animated: true)
}
Objective-C
- (void)onRequestSurchargeConfirm:(CoreBinLookupResponse *)binLookupResponse {
NSString *message = [NSString stringWithFormat:
@"Surcharge fee: %@\nConfirm?",
binLookupResponse.surcharge.amount];
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Surcharge"
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Accept"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[[WTPSTerminal singleton] confirmSurchargeFee:YES];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Decline"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action) {
[[WTPSTerminal singleton] confirmSurchargeFee:NO];
}]];
[self presentViewController:alert animated:YES completion:nil];
}
Step 4. Handle reversal errors
If the automatic reversal fails, for example because of a network interruption, the SDK calls onSurchargeReversalError: with the original CoreSaleResponse. Our gateway authorized the sale, but the reversal didn't complete.
To handle a failed reversal, store the uniqueRef of the sale, and then call terminal.processReversal to try again. The following example handles a failed reversal:
Swift
func onSurchargeReversalError(_ saleResponse: CoreSaleResponse!) {
guard let saleResponse = saleResponse else { return }
// Our gateway authorized the sale but the reversal failed.
// Store the uniqueRef and retry the reversal when the device is online.
savePendingReversal(uniqueRef: saleResponse.uniqueRef)
// Mark the response as declined so that you can display it
saleResponse.code = "D"
saleResponse.status = "VOID"
saleResponse.descriptionCode = "SURCHARGE DECLINED"
openReceipt(response: saleResponse)
}
// Call this when the device is back online, using the same terminal that ran the original sale.
func retryPendingReversal(uniqueRef: String) {
let reversal = CoreReversal()
reversal.uniqueRef = uniqueRef
terminal.processReversal(reversal, isRefund: NSNumber(value: false))
}
Objective-C
- (void)onSurchargeReversalError:(CoreSaleResponse *)saleResponse {
NSLog(@"onSurchargeReversalError - uniqueRef %@ requires manual reversal",
saleResponse.uniqueRef);
// Store the uniqueRef and retry the reversal when the device is online
[self savePendingReversal:saleResponse.uniqueRef];
saleResponse.code = @"D";
saleResponse.status = @"VOID";
saleResponse.descriptionCode = @"SURCHARGE DECLINED";
[self openReceipt:saleResponse];
}
// Call this when the device is back online, using the same terminal that ran the original sale.
- (void)retryPendingReversal:(NSString *)uniqueRef {
CoreReversal *reversal = [[CoreReversal alloc] init];
reversal.uniqueRef = uniqueRef;
[[WTPSTerminal singleton] processReversal:reversal isRefund:[NSNumber numberWithBool:NO]];
}
Step 5. (Optional) Change the confirmation timeout
The SDK starts a timer when onRequestSurchargeConfirm: fires. If you don't call confirmSurchargeFee: before the timer expires, the SDK reverses the sale.
To change the timeout from the default of 30 seconds, set surchargeConfirmationTimeoutInSeconds in your device data dictionary before you initialize the device. The value must be greater than zero. If you set zero or a negative value, the SDK uses the default. The following example sets the timeout to 60 seconds:
Swift
var deviceSettings = Dictionary<String, Any>()
// Surcharge confirmation timeout - the default is 30 seconds
deviceSettings["surchargeConfirmationTimeoutInSeconds"] = 60
terminal.initDevice(APPLETTP, with: DCT_INTERNAL, withDeviceData: deviceSettings)
Objective-C
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
// Surcharge confirmation timeout - the default is 30 seconds
[data setObject:[NSNumber numberWithInt:60] forKey:@"surchargeConfirmationTimeoutInSeconds"];
[[WTPSTerminal singleton] initDevice:APPLETTP withConnectionType:DCT_INTERNAL withDeviceData:data];