Integrate the SDK

The PayButton is our own easy-to-use reference implementation for a user interface on top of the SDK.

Before starting a Custom Integration, please evaluate whether the PayButton already fulfils your needs.

To get started with your own implementation, add the SDK to your app first. Then, choose a view controller of your app. This should be the view controller that starts the payment.

We recommend to integrate the UI for the payment either into a modal or a screen separate from your checkout (e.g., the modal should be shown over the shopping cart). You have to make sure that during a transaction the user cannot change the amount, or add/delete products from the cart.
 
Also, it is important that this modal or separate screen can be closed only once 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 MERCHANT_IDENTIFIER and  MERCHANT_SECRET_KEY with your testing credentials. Uncomment the correct value for your 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];



    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 his/her 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 and what they mean can be found here.

Create a button and connect it with the transaction action. In your payment UI, add two UILabels that display the contents of details.information[0] and details.information[1] each time statusChange is called. This way, the merchant always receives detailed status information about the transaction.
 
Then, for the Bluetooth Miura reader, pair the reader with your device.
 
Start the app and tap your button. Follow the instructions on the reader and in the app. Do not worry about charging your card, it is just a test transaction.
 
Nice! You just processed the first transaction from your app.

Let the Merchant abort the transaction

You have to add a button in the app to enable the merchant to abort the transaction.

For this, add a button in your payment UI. Aborting a transaction is not always possible, e.g. it is not possible to abort in the last stage of a transaction. Therefore, show/hide your 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 aborts the transaction:

- (IBAction)abortTapped:(id)sender {
    [_process requestAbort];
}

Don't hide the checkout UI directly after requesting the abort, and don't show text such as 'Aborting...' by yourself. The SDK will call the completed callback once the transaction is aborted. Also, we recommend to let the transaction continue while the app is in the background.

Store Merchant Data on your Backend

Right now, 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, e.g. two different restaurants, to route the payment correctly. To support multiple merchants, store the following data on your backend:

  1. merchantIdentifier and merchantSecretKey. They identify to which merchant the payment is routed. You can create new merchants and get their credentials in the Gateway Manager.

  2. Whether the merchant is a TEST or LIVE merchant.

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> ];

Specify 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 can optionally be specified for this type of connection. For an External Accessory, this is for example a name prefix to filter for.

Different types of accessories can be connected with different methods, wrong configuration will fail when starting the transaction. Also make sure you have included the correct libraries for the accessory and connection type.

Specify 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 chargeWithAmount: with the amount and currency which you want to use.

Currencies, which you can use for your transactions are limited by the configuration of your Processing Path, wrong currency will fail when executing the transaction.

In the optionals block you can specify additional parameters that are attached to the transaction:

Method Description Visible in Applicable for
.subject Subject of the transaction. Gateway Manager all
.customIdentifier Your identifier or the transaction. Gateway Manager all
.statementDescriptor The descriptor of the transaction. Stripe Dashboard, customer's card bill Stripe
.applicationFee The fee which will be further applied to the transaction. Stripe Dashboard Stripe
.metadata Extra information to further specify the transction. Stripe Dashboard Stripe

The PayButton is our own easy-to-use reference implementation for a user interface on top of the SDK.

Before starting a Custom Integration, please evaluate whether the PayButton already fulfils your needs.

To get started with your own implementation, add the SDK to your app first. Then, choose an activity of your App. This should be the activity that starts the payment.

We recommend to integrate the UI for the payment either into a modal or a screen separate from your checkout (e.g., the modal should be shown over the shopping cart). You have to make sure that during a transaction the user cannot change the amount, or add/delete products from the cart.
 
Also, it is important that this modal or separate screen can be closed only once 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 the following code into your activity. Replace MERCHANT_IDENTIFIER and  MERCHANT_SECRET_KEY with your testing credentials. Uncomment the correct value for your reader.

void transaction() {
    final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this,
            ProviderMode.TEST,
            "MERCHANT_IDENTIFIER",
            "MERCHANT_SECRET_KEY");

    /* When using the Bluetooth Miura, use the following parameters:
    AccessoryParameters accessoryParameters = new AccessoryParameters.Builder(AccessoryFamily.MIURA_MPI)
                                                                     .bluetooth()
                                                                     .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);
                    process.continueWithCustomerSignature(bm, 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 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 and what they mean can be found here.

Create a button to call the transaction method. In your payment UI, add two TextViews that display the contents of processDetails.getInformation()[0] and  processDetails.getInformation()[1]  each time onStatusChanged is called. This way, the merchant always receives detailed status information about the transaction.

Then, for the Bluetooth Miura reader, pair the reader with your device.

Start the app and tap your button. Follow the instructions on the reader and in the app. Do not worry about charging your card, it is just a test transaction.

Nice! You just processed the first transaction from your app.

Let the Merchant abort the transaction

You have to add a button in the app to enable the merchant to abort the transaction.

For this, add a button in your payment UI. Aborting a transaction is not always possible, e.g. it is not possible to abort it in the last stage of a transaction. Therefore, show/hide your button using the canBeAborted flag in onStatusChanged:

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();
}

Don't hide the checkout UI directly after the merchant has requested the abort, and don't show text such as 'Aborting...' by yourself. The SDK will call the onCompleted callback once the transaction is aborted. Also, we recommend to let the transaction continue while the app is in the background.

Store Merchant Data on your Backend

Right now, 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, e.g. two different restaurants, to route the payment correctly. To support multiple merchants, store the following data on your backend:

  1. merchantIdentifier and merchantSecretKey. They identify to which merchant the payment is routed. You can create new merchants and get their credentials in the Gateway Manager.

  2. Whether the merchant is a TEST or LIVE merchant.

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>);

Specify the accessory

You have to 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 - 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 possible methods are mock(), bluetooth() and tcp().

Different types of accessories can be connected with different methods, wrong configuration will fail when starting the transaction. Also 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 which will be applied when searching for the accessory.

Specify the transaction

You have to 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 charge() method with the amount and currency which you want to use.

Currencies, which you can use for your transactions are limited by the configuration of your Processing Path, wrong currency will fail when executing the transaction.

After the charge() method you can specify additional, optional parameters:

Method Description Visible in Applicable for
subject() Subject of the transaction. Gateway Manager all
customIdentifier() Your identifier or the transaction. Gateway Manager all
statementDescriptor() The descriptor of the transaction. Stripe Dashboard, customer's card bill Stripe
applicationFee() The fee which will be further applied to the transaction. Stripe Dashboard Stripe
metadata() Extra information to further specify the transction. Stripe Dashboard Stripe

Can we help you?

If you cannot find your answer, contact us and we'll get in touch with you soon.

© Copyright 2017 Payworks GmbH. Legal.