Integrating the SDK
                PayButton is an easy-to-use, reference implementation for a user interface on top of the SDK. Before starting a custom integration, evaluate whether the PayButton Integration can meet your needs.
To get started with a custom integration: 
- Add the SDK to your app.
 - Choose a view controller of your app. This should be the view controller that starts the payment.
 
The recommendation is to integrate the UI for the payment in either a modal or a screen separate from your checkout (e.g., the modal should be shown over the shopping cart). This step helps ensure that a user cannot change the amount or add/delete products from the cart during a transaction.
It is important to set the modal or separate screen so that it can be closed only after the SDK calls the 
completed
 callback. Make sure to hide all Close
 or Back
 buttons until the transaction is completed. Otherwise, if such a button is tapped, the SDK will continue with the transaction, but the merchant cannot see the result.Paste the following code into the view controller implementation. Replace the 
MERCHANT_IDENTIFIER
 and MERCHANT_SECRET_KEY
 with your testing credentials. Uncomment the correct value for your card reader.- (IBAction)transaction:(id)sender { MPTransactionProvider* transactionProvider = [MPMpos transactionProviderForMode:MPProviderModeTEST merchantIdentifier:@"MERCHANT_IDENTIFIER" merchantSecretKey:@"MERCHANT_SECRET_KEY"]; MPTransactionParameters *transactionParameters = [MPTransactionParameters chargeWithAmount:[NSDecimalNumber decimalNumberWithString:@"5.00"] currency:MPCurrencyEUR optionals:^(id<MPTransactionParametersOptionals> _Nonnull optionals) { optionals.subject = @"Bouquet of Flowers"; optionals.customIdentifier = @"yourReferenceForTheTransaction"; }]; // When using the Bluetooth Miura, use the following parameters: // MPAccessoryParameters *ap = [MPAccessoryParameters externalAccessoryParametersWithFamily:MPAccessoryFamilyMiuraMPI // protocol:@"com.miura.shuttle" // optionals:nil]; // When using Verifone readers via WiFi or Ethernet, use the following parameters: // MPAccessoryParameters *ap = [MPAccessoryParameters tcpAccessoryParametersWithFamily:MPAccessoryFamilyVerifoneVIPA // remote:@"192.168.254.123" // port:16107 // optionals:nil]; MPTransactionProcess *process = [transactionProvider startTransactionWithParameters:transactionParameters accessoryParameters:ap registered:^(MPTransactionProcess *process, MPTransaction *transaction) { NSLog(@"registered MPTransactionProcess, transaction id: %@", transaction.identifier); } statusChanged:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionProcessDetails *details) { NSLog(@"%@\n%@", details.information[0], details.information[1]); } actionRequired:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionAction action, MPTransactionActionSupport *support) { switch (action) { case MPTransactionActionCustomerSignature: { NSLog(@"show a UI that let's the customer provide their signature!"); // In a live app, this image comes from your signature screen UIGraphicsBeginImageContext(CGSizeMake(1, 1)); UIImage *capturedSignature = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [process continueWithCustomerSignature:capturedSignature verified:YES]; // Add this instead, if you would like to collect the customer signature on the printed merchant receipt [process continueWithCustomerSignatureOnReceipt]; break; } case MPTransactionActionCustomerIdentification: { // always return NO here [process continueWithCustomerIdentityVerified:NO]; break; } case MPTransactionActionApplicationSelection: { // This happens only for readers that don't support application selection on their screen break; } default: { break; } } } completed:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionProcessDetails *details) { NSLog(@"Transaction ended, transaction status is %lu", (unsigned long) transaction.status); if (details.state == MPTransactionProcessDetailsStateApproved) { // Ask the merchant, whether the shopper wants to have a receipt // and close the checkout UI } else { // Allow your merchant to try another transaction } // only close your modal here }]; }
More information on the completed transaction statuses is available here.
To ensure that the merchant always receives detailed status information about the transaction:
- Create a button and connect it with thetransactionaction.
 - In your payment UI, add twoUILabelsthat display the contents of thedetails.information[0]anddetails.information[1]each time thestatusChangeis called.
 
For the Bluetooth Miura card reader, pair the reader with your device. Then, follow these steps:
- Start the app and tap your button.
 - Follow the instructions on the reader and in the app. The test transaction will not charge your card. You just processed the first transaction from your app.
 
Enabling Merchants to Abort Transactions
You have the option to enable merchants to abort transactions. The feature is usually displayed on the card reader as a red "X". However, it is recommended that you create an in-app button to enable the merchant to abort the transaction.
Aborting a transaction is not always possible in different stages of the transaction. For example, it is not possible to abort in the last stage of a transaction. Therefore, show/hide your 
Abort
 button using the canBeAborted
 flag in statusChanged
:statusChanged:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionProcessDetails *details) { _abortButton.hidden = ![transaction canBeAborted]; }
Then, create an action for the 
Abort
 button that enables the merchant to abort the transaction:Do not hide the checkout UI directly after requesting the abort, and do not display messages such as '"Aborting..." by yourself. The SDK will call the- (IBAction)abortTapped:(id)sender { [_process requestAbort]; }
completed
 callback after the transaction is aborted. Also, we recommend letting the transaction continue while the app is in the background.
                Storing Merchant Data on Your Backend
Currently, you have hardcoded the 
merchantIdentifier
 and merchantSecretKey
. This means that all payments would be routed to the same merchant.For a live solution, you might want to support multiple merchants, such as two different restaurants, to route the payment correctly. To support multiple merchants, store this data on your backend: 
- merchantIdentifierandmerchantSecretKeyto identify which merchant the payment is routed to. You can create new merchants and get their credentials in the Gateway Manager.
 - Whether the merchant is aTESTorLIVEmerchant.
 
You can then fetch this data before a transaction and configure the SDK correctly: 
MPTransactionProvider* transactionProvider = [MPMpos transactionProviderForMode:<TEST or LIVE, loaded from your backend> merchantIdentifier:<MerchantIdentifier loaded from your backend> merchantSecretKey:<MerchantSecretKey loaded from your backend> ];
Specifying the Accessory
You have to specify which accessory you want to use with your app and how to connect to it by defining an 
MPAccessoryParameters
 object, which you can create with the provided class helper methods. The MPAccessoryFamily
-is type of accessory that you want to connect to. The optionals block provides access to all parameters that you have the optional to specify for this type of connection. For example, for an External Accessory, this is a name prefix to filter for.Different types of accessories can be connected with different methods. An incorrect configurations will fail when starting the transaction. Make sure to include the correct libraries for the accessory and connection type.
Specifying the Transaction
You have to specify the parameters of the transaction you want to execute with a 
MPTransactionParameters
 object, which you can create with the provided class methods.For charge transactions call the 
chargeWithAmount:
 with the amount and currency that you want to use.The currencies that you can use for your transactions are limited by the configuration of your Processing Path. An incorrect currency will fail when executing the transaction. In the optionals block you can specify the following additional methods that are attached to the transaction:
Method  | Description  | Visible in  | Applicable for  | 
.subject   | Subject of the transaction  | Gateway Manager  | All  | 
.customIdentifier   | Your custom identifier for the transaction  | Gateway Manager  | All  | 
.statementDescriptor   | Descriptor of the transaction  | Stripe Dashboard, Customer's payment card statement  | Stripe  | 
.applicationFee   | Fee that will be further applied to the transaction  | Stripe Dashboard  | Stripe  | 
.metadata   | Extra information to further specify the transaction  | Stripe Dashboard  | Stripe  | 
Integrating the
                  SDK
                PayButton is an easy-to-use, reference implementation for a user interface on top
                  of the SDK. Before starting a custom integration, evaluate whether the PayButton Integration can meet your needs.
To get started with a custom integration: 
- Add the SDK to your app.
 - Choose a view controller of your app. This should be the view controller that starts the payment.
 
The recommendation is to integrate the UI for the payment in either a modal or a
                  screen separate from your checkout (e.g., the modal should be shown over the
                  shopping cart). This step helps ensure that a user cannot change the amount, or
                  add/delete products from the cart during a transaction.
It is important to set the modal or separate screen so that it can be closed only
                  after the SDK calls the 
onCompleted
 callback.
                  Make sure to hide all Close
 or Back
                  buttons until the transaction is completed. Otherwise, if such a button is tapped,
                  the SDK will continue with the transaction, but the merchant cannot see the
                  result.Paste this code into the view controller implementation. Replace the
                    
MERCHANT_IDENTIFIER
 and MERCHANT_SECRET_KEY
                  with your testing credentials, or use TransactionProvider
 in
                  mocked mode. Use the correct value of AccessoryParameters
 for
                  your reader.void transaction() { final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this, ProviderMode.TEST, "MERCHANT_IDENTIFIER", "MERCHANT_SECRET_KEY"); /* For starting transaction in mocked mode use fallowing provider: final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this, ProviderMode.MOCK, "merchantIdentifier", "merchantSecretKey"); */ /* When using the Bluetooth Miura, use the following parameters: */ AccessoryParameters accessoryParameters = new AccessoryParameters.Builder(AccessoryFamily.MIURA_MPI) .bluetooth() .build(); /* When using Verifone readers via WiFi or Ethernet, use the following parameters: AccessoryParameters accessoryParameters = new AccessoryParameters.Builder(AccessoryFamily.VERIFONE_VIPA) .tcp("192.168.254.123", 16107) .build(); */ TransactionParameters transactionParameters = new TransactionParameters.Builder() .charge(new BigDecimal("5.00"), io.mpos.transactions.Currency.EUR) .subject("Bouquet of Flowers") .customIdentifier("yourReferenceForTheTransaction") .build(); TransactionProcess paymentProcess = transactionProvider.startTransaction(transactionParameters, accessoryParameters, new TransactionProcessWithRegistrationListener() { @Override public void onRegistered(TransactionProcess process, Transaction transaction) { Log.d("mpos", "transaction identifier is: " + transaction.getIdentifier() + ". Store it in your backend so that you can always query its status."); } @Override public void onStatusChanged(TransactionProcess process , Transaction transaction, TransactionProcessDetails processDetails) { Log.d("mpos", "status changed: " + Arrays.toString(processDetails.getInformation())); } @Override public void onCustomerSignatureRequired(TransactionProcess process, Transaction transaction) { // in a live app, this image comes from your signature screen Bitmap.Config conf = Bitmap.Config.ARGB_8888; Bitmap bm = Bitmap.createBitmap(1, 1, conf); byte[] signature = BitmapHelper.byteArrayFromBitmap(bm); process.continueWithCustomerSignature(signature, true); } @Override public void onCustomerVerificationRequired(TransactionProcess process, Transaction transaction) { // always return false here process.continueWithCustomerIdentityVerified(false); } @Override public void onApplicationSelectionRequired(TransactionProcess process, Transaction transaction, List<ApplicationInformation> applicationInformation) { // This happens only for readers that don't support application selection on their screen process.continueWithSelectedApplication(applicationInformation.get(0)); } @Override public void onDccSelectionRequired(TransactionProcess transactionProcess, Transaction transaction, DccInformation dccInformation) { // This comes up if the DCC selection cannot be done on the terminal itself transactionProcess.continueDccSelectionWithOriginalAmount(); } @Override public void onCreditDebitSelectionRequired(TransactionProcess transactionProcess, Transaction transaction) { // leave empty if your application does not support US Credit/Debit selection, otherwise // to continue transaction with credit scheme selected call: transactionProcess.continueCreditDebitSelectionWithCredit(); // or to continue transaction with debit scheme selected call: transactionProcess.continueCreditDebitSelectionWithDebit(); } @Override public void onCheckingSavingsSelectionRequired(TransactionProcess transactionProcess, Transaction transaction) { // leave empty if your application does not support Canada Interac card scheme // to continue transaction with savings account selected call: transactionProcess.continueCheckingSavingsSelectionWithSavings(); // or to continue transaction with checking account selected call: transactionProcess.continueCheckingSavingsSelectionWithChecking(); } @Override public void onCompleted(TransactionProcess process, Transaction transaction, TransactionProcessDetails processDetails) { Log.d("mpos", "completed"); if (processDetails.getState() == TransactionProcessDetailsState.APPROVED) { // print the merchant receipt Receipt merchantReceipt = transaction.getMerchantReceipt(); // print a signature line if required if(merchantReceipt.isSignatureLineRequired()) { System.out.println(""); System.out.println(""); System.out.println(""); System.out.println("------ PLEASE SIGN HERE ------"); } // ask the merchant, whether the shopper wants to have a receipt Receipt customerReceipt = transaction.getCustomerReceipt(); // and close the checkout UI } else { // Allow your merchant to try another transaction } } }); } @Override public void onBackPressed() { Toast.makeText(this, "The back button is disabled during a transaction. Please use the 'abort' button to cancel the transaction.", Toast.LENGTH_LONG).show(); }
More information on the completed transaction statuses is available here.
To ensure that the merchant always receives detailed status information about the
                  transaction:
- Create a button to call thetransactionmethod.
 - In your payment UI, add twoTextViewsthat display the contents ofprocessDetails.getInformation()[0]andprocessDetails.getInformation()[1]each timeonStatusChangedis called.
 
For the Bluetooth Miura card reader, pair the
                    reader with your device. Then, follow these steps:
- Start the app and tap your button.
 - Follow the instructions on the reader and in the app. The test transaction will not charge your card. You just processed the first transaction from your app.
 
Enabling the Merchant to Abort Transactions
You have the option to enable merchants to abort transactions. The feature is
                  usually displayed on the card reader as a red "X". However, it is
                  recommended that you create an in-app button to enable the merchant to abort the
                  transaction.
Aborting a transaction is not always possible in different stages of the
                  transaction. For example, it is not possible to abort in the last stage of a
                  transaction. Therefore, show/hide your 
Abort
 button using
                    thecanBeAborted
flag inonStatusChanged
:public void onStatusChanged(TransactionProcess process , Transaction transaction, TransactionProcessDetails processDetails) { //.. abortButton.setVisibility(transaction != null && transaction.canBeAborted() ? View.VISIBLE : View.INVISIBLE); }
Then, create a click listener for the abort button that aborts the
                  transaction:
public void abort() { process.requestAbort(); }
Do not hide the checkout UI directly after the merchant has requested the abort,
                  and do not show message text such as "Aborting..." by yourself. The SDK
                  will call the 
onCompleted
 callback once the
                  transaction is aborted. Also, we recommend letting the transaction continue while
                  the app is in the background.Storing Merchant Data on Your Backend
Currently, you have hardcoded the 
merchantIdentifier
 and
                    merchantSecretKey
. This means that all payments would be routed
                  to the same merchant.For a live solution, you might want to support multiple merchants, such as for
                  two different restaurants, to route the payment correctly. To support multiple
                  merchants, store this data on your backend:
- merchantIdentifierandmerchantSecretKeyto identify which merchant the payment is routed to. You can create new merchants and get their credentials in the Gateway Manager.
 - Whether the merchant is aTESTorLIVEmerchant.
 
You can then fetch this data before a transaction and configure the SDK
                  correctly:
final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this, <TEST or LIVE, loaded from your backend>, <MerchantIdentifier loaded from your backend>, <MerchantSecretKey loaded from your backend>);
Specifying the Accessory
You must specify which accessory you want to use with your app and how to connect
                  to it by defining an 
AccessoryParameters
 object, which you can
                  create with the provided builder.The argument, which you pass into the builder's constructor, specifies the
                    
AccessoryFamily
. This is the type of accessory that you want to
                  connect to.The method, which you call right after the constructor, specifies the connection
                  type that you want to use. Currently available methods are
                  
mock()
, bluetooth()
 and
                  tcp()
.Different types of accessories can be connected with different methods. An
                  incorrect configuration will fail when starting the transaction. Make sure you
                  have included the correct libraries for the accessory and connection type.
After the second method, depending on which connection type you selected, you can
                  set different options specifying the connection. For example, for Bluetooth you
                  can select an address prefix that will be applied when searching for the
                  accessory.
Specifying the Transaction
You must specify the parameters of the transaction you want to execute with a
                    
TransactionParameters
 object, which you can create with the
                  provided builder.For charge transactions call the 
charge()
 method with the amount
                  and currency that you want to use.The currencies that you can use for your transactions are limited by the
                  configuration of your Processing Path. An incorrect currency will fail when
                  executing the transaction.
After the 
charge()
 method, you can specify these other optional
                  methods:- Method
 - subject()
 - Description
 - Subject of the transaction
 - Visible in
 - Gateway Manager
 - Applicable for
 - All
 
- Method
 - customIdentifier()
 - Description
 - Your custom identifier for the transaction
 - Visible in
 - Gateway Manager
 - Applicable for
 - All
 
- Method
 - statementDescriptor()
 - Description
 - Descriptor of the transaction
 - Visible in
 - Stripe Dashboard, Customer's payment card statement
 - Applicable for
 - Stripe
 
- Method
 - applicationFee()
 - Description
 - Fee that will be further applied to the transaction
 - Visible in
 - Stripe Dashboard
 - Applicable for
 - Stripe
 
- Method
 - metadata()
 - Description
 - Extra information to further specify the transaction
 - Visible in
 - Stripe Dashboard
 - Applicable for
 - Stripe