Existing customers: Get your sandbox and production credentials for Heartland/Portico integration.
This SDK makes it easy to integrate your iOS apps with our Portico Gateway API.
Our iOS-SDK is available through CocoaPods. To install it, simply add the following line to your Podfile and run "pod update":
pod GlobalPayments-iOS-SDKThe SDK manages the communication with the device and the gateway. Neither the SDK nor the device maintains a copy of the merchant account credentials used. These need to be set by your application at runtime. Below, you'll find the code snippets to use for SDK imports and configuring the SDK with credentials.
#import <Heartland_iOS_SDK/Heartland-iOS-SDK-umbrella.h>
#import <Heartland_iOS_SDK/Heartland_iOS_SDK-Swift.h> HpsConnectionConfig *config = [[HpsConnectionConfig alloc] init];
config.versionNumber = @"3409";
config.developerID = @"002914";
config.username = @"xxxxxxxxx";
config.password = @"xxxxxxxxx";
config.siteID = @"xxxxxx";
config.deviceID = @"xxxxxx";
config.licenseID = @"xxxxxx";
self.device = [[HpsC2xDevice alloc] initWithConfig:config];
}))Before creating a Bluetooth connection with the device, your application requires some additional code in the form of a device listener or delegate object. Here’s a brief description of each of the available methods and how they can assist in your application development:
onBluetoothDeviceFound – As the Bluetooth scanning process continues, this method will be called by the SDK as soon as a device is found, allowing your application to immediately update its UI to present this information to the user.onBluetoothDeviceList – Once the Bluetooth scanning process completes, this method will be called by the SDK, signaling that no additional devices are currently available. The user should select one of the available devices or check their settings before initiating another Bluetooth scan.onConnected – This method will be called by the SDK once a successful Bluetooth connection has been established with the selected device.onDisconnected – This method will be called by the SDK when the Bluetooth connection has been lost.onError – This method will be called by the SDK if any errors occur during the Bluetooth connection process.onTerminalInfoReceived – This method may be called by the SDK if any information about the device is available.Your application will need to initiate the Bluetooth scanning process by calling the initialize method on the `device`` object. Any progress along the way will be indicated by the SDK calling the appropriate method on your application’s device listener or delegate object.
Once the user selects the correct Bluetooth device, your application will need to update the SDK by calling the connectDevice method on the device object. This method will require an object obtained by either the onBluetoothDeviceFound method or the onBluetoothDeviceList method.
@interface MyDeviceDelegate : NSObject<HpsC2xDeviceDelegate>
@end
@implementation MyDeviceDelegate
- (void)onBluetoothDeviceList:(NSMutableArray *)peripherals {
// receive list of available bluetooth devices
// present to user for selection/confirmation
// connect to the selected device
[self.device connectDevice:[peripherals objectAtIndex:i]];
}
- (void)onConnected {
// device is connected
// allow processing
}
- (void)onDisconnected {
// device is not connected
// do not allow processing
}
- (void)onError:(NSString*)deviceError {
// handle errors
}
- (void)onTerminalInfoReceived:(HpsTerminalInfo *)terminalInfo {
// handle received device information
}
@end
device.deviceDelegate = [[MyDeviceDelegate alloc] init];
// initiate a bluetooth scan
[device initialize];
}))If you want to use a USB or Lightning connection instead of Bluetooth, you can use Moby 5500.
Just like with Bluetooth, you'll need to set up the same DeviceListener shown above in the Bluetooth Pairing section above. Your application will initiate the connection process by calling the initialize method on the device object. The onConnected method will be called when the connection is established.
Before starting a transaction request, your application requires some additional code in the form of a transaction listener / delegate object. Here’s a brief description of each of the available methods and how they can assist in your application development:
onStatusUpdate – As the EMV process occurs, this method will be called by the SDK when the device may need to prompt the user with information about the current status. Any status update received by this method should be displayed to the user.onConfirmApplication – As the EMV process occurs, this method will be called by the SDK when the card holder needs to select an EMV application.onConfirmAmount – As the EMV process occurs, this method will be called by the SDK when the card holder needs to confirm the final authorization amount.onTransactionCompleted – Once the authorization request has been submitted to the gateway, this method will be called by the SDK, passing the authorization response to your application.onTransactionCancelled – This method will be called by the SDK if the transaction is cancelled by the device at any point.onError – This method will be called by the SDK if any errors occur during the transaction process. @interface MyTransactionDelegate : NSObject<HpsC2xTransactionDelegate>
@end
@implementation MyTransactionDelegate
- (void)onStatusUpdate:(HpsTransactionStatus)transactionStatus {
// inform user of status updates
}
- (void)onConfirmApplication:(NSArray<AID *> *)applications {
// prompt user to select desired application
[self.device confirmApplication:[applications objectAtIndex:0]];
}
- (void)onConfirmAmount:(NSDecimal)amount {
// prompt user to confirm final amount
[self.device confirmAmount:amount];
}
- (void)onTransactionComplete:(HpsTerminalResponse *)response {
// handle response
}
- (void)onTransactionCancelled {
// handle cancellation
}
- (void)onError:(NSError *)emvError {
// handler errors
}
@end
device.transactionDelegate = [[MyTransactionDelegate alloc] init];
}))Our SDK comes with two builders to help you get set up to start processing transactions quickly, one for transactions initiated using manual entry and another for transactions using tap, insert, or swipe methods.
Your application will need to initiate the transaction request process by creating the correct request builder, preparing any required data or information, and executing the builder. Any progress along the way will be indicated by the SDK calling the appropriate method on your application’s transaction listener or delegate object. Example code for these methods is provided below.
Note: Required device kernel and firmware version: ANHE_Kernel 4.3g_v8, and its firmware version is 1.00.03.45
// Initiate Transaction – CreditAuth – Manual Entry (example code)
HpsCreditCard *card = [[HpsCreditCard alloc] init];
card.cardNumber = @"424242******4242";
card.expMonth = 12;
card.expYear = 2025;
card.cvv = @"123";
HpsC2xCreditAuthBuilder *builder = [[HpsC2xCreditAuthBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc] initWithDouble:10.00];
builder.creditCard = card;
[builder execute];// Initiate Transaction – CreditAuth – Tap/Insert/Swipe (example code)
HpsC2xCreditAuthBuilder *builder = [[HpsC2xCreditAuthBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc] initWithDouble:10.00];
[builder execute];// Initiate Transaction – CreditAddToBatch (example code)
HpsC2xCreditCaptureBuilder *builder = [[HpsC2xCreditCaptureBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc]initWithDouble:10.00];
builder.transactionId = transactionId;
[builder execute];// Initiate Transaction – CreditSale – Manual Entry (example code)
HpsCreditCard *card = [[HpsCreditCard alloc] init];
card.cardNumber = @"424242******4242";
card.expMonth = 12;
card.expYear = 2025;
card.cvv = @"123";
HpsC2xCreditSaleBuilder *builder = [[HpsC2xCreditSaleBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc] initWithDouble:10.00];
builder.creditCard = card;
[builder execute];// Initiate Transaction – CreditSale – Dip/Swipe (example code)
HpsC2xCreditSaleBuilder *builder = [[HpsC2xCreditSaleBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc] initWithDouble:10.00];
[builder execute];// Initiate Transaction – Tip Adjust (example code)
HpsC2xCreditAdjustBuilder *builder = [[HpsC2xCreditAdjustBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc]initWithDouble: 12.00];
builder.gratuity = [[NSDecimalNumber alloc]initWithDouble: 2.00];
builder.transactionId = transactionId;
[builder execute];// Initiate Transaction – CreditReturn by Transaction ID (example code)
HpsC2xCreditReturnBuilder *builder = [[HpsC2xCreditReturnBuilder alloc] initWithDevice:device];
builder.amount = [[NSDecimalNumber alloc]initWithDouble:1.00];
builder.transactionId = transactionId;
[builder execute];// Initiate Transaction – CreditReversal due to timeout (example code)
HpsC2xCreditReversalBuilder *b = [[HpsC2xCreditReversalBuilder alloc] initWithDevice:self.device];
b.clientTransactionId = originalResponse.clientTransactionIdUUID;
b.reason = ReversalReasonCodeTIMEOUT;
b.amount = builder.amount;
[builder execute];// Initiate Transaction – CreditVoid (example code)
HpsC2xCreditVoidBuilder *builder = [[HpsC2xCreditVoidBuilder alloc] initWithDevice:device];
builder.transactionId = transactionId;
[builder execute];
}))To use your own Client Transaction ID, set the value that you want by using the setReferenceNumber method of the builder, as shown below. If you do not set your own reference number, a transaction ID will be generated automatically.
//Set the reference number
builder.clientTransactionId(yourClientTxnId);
}))Once the transaction is complete, you will see the same value returned inside the TerminalResponse object parameter of onTransactionComplete.
The SDK supports OTA updates for the C2X firmware and configuration. These updates improve device functionality without requiring manual installation. You'll need to establish a Bluetooth connection with the device to check for and install updates. The first step is for your application to request the available versions for either firmware or config.
import Foundation
import Heartland_iOS_SDK
import UIKit
class ViewController: UIViewController {
var device: HpsC2xDevice? {
didSet {
device?.otaFirmwareUpdateDelegate = self
}
}
@IBAction func checkForUpdatesButtonAction(_: Any) {
device.requestTerminalVersionData()
}
}
}))The ViewController class must conform to the GMSDeviceFirmwareUpdateDelegate to handle responses from the device. The code triggers the onTerminalVersionDetails callback, which retrieves and displays the current firmware version installed on the device:
var currentFirmwareVersion: String = "" {
didSet {
device?.getAllVersionsForC2X()
}
}
extension ViewController: GMSDeviceFirmwareUpdateDelegate {
func onTerminalVersionDetails(info: [AnyHashable: Any]?) {
if let info = info, let firmwareVersion = info["firmwareVersion"],
let stringFirmwareVersion = firmwareVersion as? String
{
print("Info: \(stringFirmwareVersion)")
self.currentFirmwareVersion = stringFirmwareVersion
}
}
}
}))When the code triggers the onTerminalVersionDetails callback, it retrieves and displays the latest firmware version:
var lastFirmwareVersion: String = "" {
didSet {
self.compareVersions()
}
}
extension ViewController: GMSDeviceFirmwareUpdateDelegate {
func listOfVersionsFor(results: [Any]?) {
if let results = results,
let lastVersion = results.reversed().first as? [String: AnyObject],
let firmwareVersion = lastVersion.first?.value {
lastFirmwareVersion = firmwareVersion as? String ?? ""
print(firmwareVersion)
}
}
}Now, we can compare the currentFirmwareVersion and latestFirmwareVersion:
func compareVersions() {
let versionCompare = currentFirmwareVersion
.compare(lastFirmwareVersion, options: .numeric)
if versionCompare == .orderedAscending {
// There is a new update
} else {
// No new update
}
}
}))Assuming there is a new update, we can request update to C2X, supplying the latest firmware version:
@IBAction func updateFirmwareButtonAction(_: Any) {
device.setVersionDataFor(versionString: lastFirmwareVersion)
device.requestUpdateVersionForC2X()
}
}))We can also handle the callbacks of the device in these functions:
extension ViewController: GMSDeviceFirmwareUpdateDelegate {
func terminalOTAResult(resultType: TerminalOTAResult,
info _: [String: AnyObject]?,
error _: Error?) {}
func otaUpdateProgress(percentage: Float) {}
func onReturnSetTargetVersion(message _: String) {}
}
}))Surcharge functionality allows merchants to apply a percentage fee on credit card transactions. Surcharge is supported for specific transaction types: credit sale, credit authorization, and manual card entry. To see a working example of how to enable surcharge, check out our sample Xcode project in the SDK GitHub repo.
With surcharge enabled, a 3% charge (default value) will be added to the total for sale or auth transactions that use a credit card. No charge is added if the card type is unable to be detected.
To enable surcharge, you need to configure the transaction builder:
let builder = HpsC2xCreditAuthBuilder(device: device)
builder.isSurchargeEnabled = true
...Operations for credit sale, credit auth, manual card entry
builder.execute()
}))By default, the surcharge is calculated at 3%, but you can set a custom percentage between 2% and 3%. You can use the code below to set a custom percentage for the surcharge:
builder.surchargeFee = NSDecimalNumber(string: "2.75")
}))With surcharge enabled, an approved payment transaction response includes surcharge information including the fee percentage and the surcharge amount:
let surchargeFee = (Decimal(string: response.surchargeFee ?? "0") ?? 0) * 100
}))let surchargeAmount = NSDecimalNumber(string: response.surchargeAmount ?? "0")
}))if case response.surchargeRequested = SurchargeEligibility.Y { }
if case response.surchargeRequested = SurchargeEligibility.N { }
if case response.surchargeRequested = SurchargeEligibility.U { }| Code | Definition |
|---|---|
| Y | Yes - Eligible for surcharge |
| N | No - Not eligible for surcharge |
| U | Unknown - Eligibility is unknown |
Note: Eligibility of Unknown should be rare. It exists to ensure that the core payment transaction is not rejected in any scenario where eligibility cannot be fully verified.
Surcharge requires that the cardholder is given the opportunity to approve or decline the charge. So, if you want to enable surcharge, you'll need to add the new cardholder interaction type of .surchargeRequested as shown below. Note that no fee is applied if the card type cannot be determined. This interaction request will occur only when surcharge is enabled and the card is determined to be a credit card:
func onTransactionWaitingForSurchargeConfirmation(
result: HpsTransactionStatus, response: HpsTerminalResponse
) {
if result == .surchargeRequested, let builder = self.builder,
let surchargeFee = response.surchargeFee {
let alertController = UIAlertController(title: "Surcharge Confirmation Required",
message: "There will be a \(surchargeFee) surcharge added to your purchase",
preferredStyle: .alert)
// Create the actions
let okAction = UIAlertAction(
title: "Accept",
style: UIAlertAction.Style.default
) {
UIAlertAction in
NSLog("OK Pressed")
self.device?.confirmSurcharge(true)
}
let cancelAction = UIAlertAction(
title: "Decline",
style: UIAlertAction.Style.cancel
) {
UIAlertAction in
NSLog("Cancel Pressed")
self.device?.confirmSurcharge(false)
self.showProgress(false)
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.present(alertController, animated: true, completion: nil)
}
}If you run into trouble with your application, check out the list below for some basic troubleshooting steps. Chances are pretty good that you'll find your solution. We're always here to help, though. So if you can't find the solution, use the Developer Support link at the bottom of the page to contact us.