STEP 4 Configure a payment

Executing a payment transaction between a mobile wallet app and an acceptance terminal - such as a POS, a fuel pump, or an ATM - requires both the app and the terminal to send and receive information about the transaction through the Paydiant platform.

Data Triangle

A given transaction might have numerous exchanges of data before completion, depending on its complexity, but in the simplest representation:

  1. The transaction is initiated by either the mobile wallet app or the acceptance terminal through a checkout token request.
  2. The non-initiating participant then scans and decodes the checkout token and requests to join the transaction represented by the token.
  3. The acceptance terminal communicates the amount owed.
  4. The app submits the consumer's consent to pay the amount owed, along with the selected payment account.
  5. Paydiant contacts the 3rd party processor responsible for authorizing payments for the selected tender and communicates the result to the acceptance terminal.
  6. The acceptance terminal completes the transaction and Paydiant issues a receipt to the app.

Along the way, many other circumstances are possible:

  • The consumer may wish to add a tip
  • The consumer may wish to apply a coupon discount
  • The consumer may wish to split the payment across multiple tenders, such as a gift card and a credit card.
  • The acceptance terminal may need to record points earned toward a loyalty rewards program

Regardless of the type and complexity of the transaction or the number of steps to process it, transaction data is passed between the mobile app, the acceptance terminal, and the Paydiant platform through the following two methods:

  • retrieveTransactionData requests updated information about the transaction.
  • updateTransation submits relevant data to progress the transaction forward.

Each of these calls includes a property that identifies the flow rule associated with the call instance. The flow rule indicates the current state of the transaction that the call addresses. Thus, the data passed in the call is contingent on the flow rule value.

BASIC PAYMENT IMPLEMENTATION STEPS

  1. Display or scan the QR Code.
  2. Get transaction details submitted by POS.
  3. Prompt user to select an eligible tender.
  4. Submit the payment information.
  5. Display a payment confirmation summary.

1. Display or scan the QR Code

To initiate a transaction on the Paydiant platform, one of the transaction participants (the mobile app or the acceptance terminal) must request a checkout token and generate a QR Code that can be scanned and decoded by the other participant so both parties are connected to the same transaction.

Implement the set of calls corresponding to the manner in which the mobile app will engage in the transaction.

Code-on-Phone

In the Code-on-Phone transaction initiation use case, the mobile app requests the checkout token and displays the generated QR Code for the POS or other acceptance point to scan.

IMPLEMENTATION STEPS

  1. Call obtainCheckoutToken
  2. Generate & display QR Code

1. Call obtainCheckoutToken

  1. Initialize the Transaction facade.
  2. Invoke obtainCheckoutToken for the applicable transaction type.
  3. Capture the checkoutToken value returned in the response and handle the failure block.
    {
        PDTransactionCoordinator *transactionCoordinator = [[PDTransactionCoordinator alloc] init];
        [transactionCoordinator obtainCheckoutTokenFor:kPDTransactionTypePurchase completionBlock:^(NSString *checkoutToken, PDTransactionType type) {
            handler(checkoutToken, nil);
        } failureBlock:^(PDPaydiantError *transactionError) {
            handler(nil, transactionError);
        }];
    }

2. Generate & display QR Code

{
    UIImage *qrImage = nil;
    NSString *urlString = [NSString stringWithFormat:@"%@%@", @"https://chart.googleapis.com/chart?chs=150x150&chld=L%7C0&cht=qr&chl=", checkoutToken];
    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
    qrImage = [[UIImage alloc] initWithData:imageData];

    return qrImage;
}

Tip: As a Best Practice, Paydiant advises setting the brightness level of the screen to 80% while displaying the QR Code for optimum scanning.

Note: If the app changes screens or is put into the background before the QR Code has been scanned, invoke releaseCheckoutToken and obtain a new token the transaction is reengaged.

Code-on-POS

In the Code-on-POS transaction initiation use case, the acceptance point (such as a POS or ATM) requests the checkout token and displays the generated QR Code for the mobile app to scan.

IMPLEMENTATION STEPS

  1. Call startDecoderSession
  2. Call decodeImage
  3. Call endDecoderSession

1. Call startDecoderSession

When the POS displays a QR code for the transaction, and the user correspondingly initiates a payment in the app in whatever way the app has designed that function, the app must engage the mobile device's camera. The Paydiant Decoder facade provides a wrapper that handles this behavior in the device.

{
    self.scanView.hidden  = NO;
    self.displayCodeView.hidden = YES;

    [self.decoderCoordinator startDecoderSession:self.scanView frameRect:self.scanView.frame];

    if (self.decoderCoordinator && !self.decoderCoordinator.delegate)
    {
        self.decoderCoordinator.delegate = (id)self;
    }
}

2. Call decodeImage

Once the code is captured, invoke the call to convert the QR Code back into the checkoutToken value for use in all subsequent calls related to the transaction.

- (void)decoderCoordinator:(PDDecoderCoordinator *)decoderCoordinator didFinishImage:(UIImage *)image decoding:(NSString *)qrCode {

3. Call endDecoderSession

Once the checkoutToken value is secured, release the device camera and return focus to the app. The best practice is to configure the decoder success delegate didFinishImage to invoke this call.

{
    [self.decoderCoordinator setDelegate:nil];
    [self.decoderCoordinator endDecoderSession];
    self.scanView.hidden = YES;
}

2. Get transaction details submitted by POS

Upon successful initiation of the transaction by either retrieval or scanning of the checkout token, the mobile app must request the relevant transaction information submitted by the POS, such as the amount due, which payment tenders are supported, whether discounts or tips are eligible for this transaction, etc.

First, submit the retrieveTransactionMetaData request call, passing the previously obtained checkoutToken value and specifying DISCOVERY as the current flow rule and configure blocking until paydiantReferenceId and supportedTenderTypes are returned.

    [CommonUtil showProgressIndicatorOnView:self enableUserInteraction:YES];
    PDTransactionCoordinator *transactionCoordinator = [[PDTransactionCoordinator alloc] init];
    PDRetrieveTransactionMetaDataRequest *txnRequest = [[PDRetrieveTransactionMetaDataRequest alloc] init];
    txnRequest.checkoutToken = [[PDMetaDataCheckoutToken alloc] init];
    txnRequest.checkoutToken.checkoutTokenValue = self.checkoutToken;
    txnRequest.executingTransactionFlowRule = kPDTransactionFlowRuleRetrieveTransactionMetaDataDiscovery;

    [self.eligiblePaymentAccounts removeAllObjects];
    [self.eligibleOffers removeAllObjects];

    __block NSString *paydiantReferenceId;
    __block NSArray *supportedTenderTypes;

Next, configure the success and failure blocks to handle the possible responses from the platform and continue or cancel the transaction accordingly. For example, if the current user's registered payment accounts don't match any of the supported tenders, the app will need to inform the user gracefully. There may also be additional data related to offers or loyalty or other transaction variations that are out of scope in this phase of the tutorial.

3. Prompt user to select an eligible tender

Determine which payment accounts are eligible for the transaction based on the returned supportedTenderTypes array and only display matching payment accounts in the mobile wallet for selection by user for payment. If none of the payment accounts in the wallet match the supported tenders, notify the user that no registered payment accounts are supported for the transaction.

[transactionCoordinator retrieveTransactionMetaData:txnRequest completionBlock:^(PDRetrieveTransactionMetaDataResponse *response) {

        supportedTenderTypes = response.transactionMetaData.tenderTypes;
        paydiantReferenceId = response.transactionKey.paydiantReferenceId;

        self.currentUpdateTransactionRequest = [[PDUpdateTransactionRequest alloc]init];
        self.currentUpdateTransactionRequest.confirmationRequired = false;
        self.currentUpdateTransactionRequest.checkoutToken = [[PDUpdateTransactionCheckoutToken alloc] init];
        self.currentUpdateTransactionRequest.checkoutToken.checkoutTokenValue = self.checkoutToken;
        self.currentUpdateTransactionRequest.transactionKey = [[PDUpdateTransactionTransactionKey alloc] init];
        self.currentUpdateTransactionRequest.transactionKey.paydiantReferenceId = paydiantReferenceId;
        self.transactionDetail = response.transactionDetail;

        self.eligiblePaymentAccounts = [self eligiblePaymentAccountsUsingTransactionInformation:supportedTenderTypes];

        if (self.eligiblePaymentAccounts.count > 0) {
            if(response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleProcessPayment ||
            response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleSubmitPaymentTenders)
            {
                self.currentUpdateTransactionRequest.executingTransactionFlowRule = response.nextExecutingTransactionFlowRule;
                if(response.nextTransactionFlowRuleSpecification.expectsPaymentTenders) {
                    [self displayEligiblePaymentAccounts];
                    }
                    } else if (response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleRetrieveTransactionMetaDataSummary) {
                    self.currentUpdateTransactionRequest.executingTransactionFlowRule = response.nextExecutingTransactionFlowRule;
                    [self retrieveTransactionMetaDataSummery:self.checkoutToken];
                    }
            else {
                [CommonUtil hideProgressIndicatorOnView:self];
                [CommonUtil displayMessageWithTitle:@"Error" andDescription:@"Flow rule doesn't support"]; }
             } else {
            // No valid accounts
            [CommonUtil hideProgressIndicatorOnView:self];
            [CommonUtil displayMessageWithTitle:@"Error" andDescription:@"There are no valid accounts in your mobile wallet for this transaction ."];
        }

4. Submit the payment information

When the user selects a payment account, submit the selection using the updateTransaction call with the executingTransactionFlowRule value set to ProcessPayment.

PDTransactionCoordinator *transactionCoordinator = [[PDTransactionCoordinator alloc] init];
[transactionCoordinator updateTransaction:self.currentUpdateTransactionRequest completionBlock:^(PDUpdateTransactionResponse *response) {
    if(response.nextExecutingTransactionFlowRule == kPDTransactionFlowRuleRetrieveTransactionMetaDataSummary) {
        [self retrieveTransactionMetaDataSummery:self.currentUpdateTransactionRequest.checkoutToken.checkoutTokenValue];
    } else {
        // Transaction status is closed , retrieve last transaction receipt summary to display.
        [CommonUtil hideProgressIndicatorOnView:self];
        [self getLastTransactionReceipt];
        self.displayCodeView.hidden = YES;
        self.scanView.hidden = YES;
        self.releaseTokenBTN.hidden = YES;
    }

5. Display a payment confirmation summary

If the updateTransaction completion block returns a nextExecutingTransactionFlowRle value of RetrieveTransactionMetaDataSummary, the transaction is complete! Retrieve the summary for the transaction, which will include the payment result and other transaction details.

PDTransactionCoordinator *transactionCoordinator = [[PDTransactionCoordinator alloc] init];
PDRetrieveTransactionMetaDataRequest *txnRequest = [[PDRetrieveTransactionMetaDataRequest alloc] init];
txnRequest.checkoutToken = [[PDMetaDataCheckoutToken alloc] init];
txnRequest.checkoutToken.checkoutTokenValue = token;
PDMetaDataTransactionKey *transactionKey = [[PDMetaDataTransactionKey alloc]init];
transactionKey.paydiantReferenceId = self.currentUpdateTransactionRequest.transactionKey.paydiantReferenceId;
txnRequest.transactionKey = transactionKey;
txnRequest.executingTransactionFlowRule = kPDTransactionFlowRuleRetrieveTransactionMetaDataSummary;

To display the receipt to the user, configure the completion block of the transaction summary retrieval call to initialize the Receipt facade, the retrieve the receipt for the last completed transaction.

[transactionCoordinator retrieveTransactionMetaData:txnRequest completionBlock:^(PDRetrieveTransactionMetaDataResponse *response) {
     [CommonUtil hideProgressIndicatorOnView:self];
     [self getLastTransactionReceipt];
     self.displayCodeView.hidden = YES;
     self.scanView.hidden = YES;
     self.releaseTokenBTN.hidden = YES;
}
Feedback