CP Application Integration Guide

Introduction

Commerce Applications extend the payment flow with additional features and value-added services (VAS). These applications can register to receive messages at various “trigger” points in a payment flow. These applications don’t run concurrently with the payment application, they run only at these defined points.


Flow

When there’s a transaction/order in progress, processing pauses between trigger points. When a Commerce Application is handling a Trigger, the payment application yields the control to that application, allowing it to interact with the customer, call a Commerce API, communciate with its server, or any number of other actions, but only for a limited time. After the CP App is done, it sends the response back for the original Trigger that started it so that the payment flow can continue. The CP application must finish its handling before the timeout period, otherwise the payment application will notify it that it has timed out, ignore any further responses, and move on with the payment flow. The timeout is configurable by the merchant and changes based on the trigger, e.g., AltPaymentRequest has a longer period of time then BasketFinalizedNotification.

_images/CP_Implementing_Trigger_flow_v4.png

@startuml
!include uml_styles.iuml
hide footbox
Title Uses CP API to request card data

participant "CP App" as cpapp order 20
participant "Payment Application" as payapp order 10
actor "Customer" as cust order 20
|||
payapp ->> cpapp: CardPresentedNotification
payapp <<- cpapp: CardDataRequest
payapp ->> cpapp: CardDataResponse
payapp <<- cpapp: CardPresentedNotification.generateResponse()
|||
@enduml

@startuml
!include uml_styles.iuml
hide footbox
Title Adjusts Basket

participant "CP App" as cpapp order 20
participant "Payment Application" as payapp order 10
actor "Customer" as cust order 20
|||
payapp ->> cpapp: BasketAdjustmentRequest
cpapp -> cpapp: Examine current basket in request,\ndecide to present options
cpapp <-> cust: Interact with customer to add offer to basket
cpapp -> cpapp: Prepare response with new items
payapp <<- cpapp: BasketAdjustmentResponse
|||
@enduml

@startuml
!include uml_styles.iuml
hide footbox
Title Gathers Business Analytics

participant "CP App" as cpapp order 20
participant "Payment Application" as payapp order 10
participant "Server" as server <<cloud>> order 20
|||
payapp ->> cpapp: TransactionEndedNotification
cpapp ->> server: Send basic transaction information
payapp <<- cpapp: TransactionEndedNotification.generateResponse()
|||
@enduml


Getting Started

Commerce Applications can be written as regular Android applications. All Commerce Messages are sent as Android Broadcasts. To receive a Commerce Message, the Commerce Application can register for the intent via the Android Manifest.

Commerce Message Types

There are three types of Commerce Messages:
  • Commerce Trigger notifications from Payment Application to Commerce Applications. These are notifications only, the payment app is not expecting any response other than to know that it can proceed with payment flow.

  • Commerce Trigger requests from Payment Application to Commerce Applications to request Commerce Applications to do something like adjust the basket.

  • Commerce APIs from Commerce Applications to the Payment Application requesting some information or service. This can only happen between a Commerce Application receiving a trigger from the payment application and sending response to the commerce trigger.

Registering for Commerce Triggers and API Responses

The manifest needs to include the following:
  • The CP Application ID

  • The version of the Commerce Trigger spec that the application is using

  • The Commerce Triggers and APIs that it needs to receive

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.commerceapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        >
        <meta-data
            android:name="com.verifone.commerce.manifest.appid"
            android:value="ExampleCpApp-695973514" />
        <meta-data
            android:name="com.verifone.commerce.manifest.trigger.version"
            android:value="4.3.0" />

        <receiver
            android:name="com.example.commerceapp.CommerceReceiver"
            android:enabled="true"
            android:exported="true">
            <meta-data
                android:name="com.verifone.commerce.manifest.trigger.type"
                android:value="service" />

            <intent-filter>
                <!-- CP Triggers -->
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_TRANSACTION_STARTED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_REQUESTS_LOYALTY" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_REQUESTS_BASKET_ADJUSTMENT" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_BASKET_FINALIZED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_REQUESTS_AMOUNT_ADJUSTMENT" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_AMOUNT_FINALIZED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_REQUESTS_ALT_PAYMENT" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_CARD_PRESENTED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_CARD_BIN_RECEIVED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_REQUESTS_PAYMENT_AMOUNT_ADJUSTMENT" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_AUTHORIZATION_COMPLETED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_PAYMENT_COMPLETED" />
                <action android:name="com.verifone.commerce.intent.action.CP_SYSTEM_NOTIFIES_TRANSACTION_ENDED" />

                <!-- CP API Responses -->
                <action android:name="com.verifone.commerce.intent.action.CP_APP_RECEIVES_CARD_DATA" />
                <action android:name="com.verifone.commerce.intent.action.CP_APP_RECEIVES_ENCRYPTED_CARD" />
                <action android:name="com.verifone.commerce.intent.action.CP_APP_RECEIVES_APPEND_RECEIPT" />

                <!-- Category -->
                <category android:name="com.verifone.commerce.intent.category.CP_MESSAGE" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

The CP App can choose to handle all messages through one receiver, or split it across multiple receivers, the above is just one example. The important part is that these must be registered through the Android Manifest, they cannot be dynamically registered.

Receiving Commerce Messages

Commerce Trigger intents contain the data that each Trigger defines as a json string as defined by the Commerce Trigger spec. The Verifone SDK provides a CommerceMessageBuilder that parses the intent into the proper Trigger class.

public void onReceive(Context context, Intent intent) {
    CommerceMessage message = CommerceMessage.CommerceMessageBuilder.buildMessageFromIntent(intent);
    if (message != null) {
        switch (message.getName()) {
            // CP Triggers
            case TransactionStartedNotification.NAME:
                break;
            case BasketAdjustmentRequest.NAME:
                break;
            case BasketFinalizedNotification.NAME:
                break;
            case LoyaltyRequest.NAME:
                break;
            case AmountAdjustmentRequest.NAME:
                break;
            case AmountFinalizedNotification.NAME:
                break;
            case AltPaymentRequest.NAME:
                break;
            case CardBinReceivedNotification.NAME:
                break;
            case CardPresentedNotification.NAME:
                break;
            case PaymentAmountAdjustmentRequest.NAME:
                break;
            case AuthorizationCompletedNotification.NAME:
                break;
            case PaymentCompletedNotification.NAME:
                break;
            case TransactionEndedNotification.NAME:
                break;

            // CP API Responses
            case AppendReceiptResponse.NAME:
                break;
            case CardDataResponse.NAME:
                break;
            case EncryptedCardResponse.NAME:
                break;

            // Best practice to have a default.
            default:
                Log.e(TAG, "Developer error, unrecognized trigger name. " + message.getName());
                break;
        }
    } else {
        Log.e(TAG, "SDK/system error parsing Commerce Message from intent. " + intent.getAction());
    }
}


Warning

Verifone Confidential

This documentation is protected by law from any form of duplication unless prior permission is obtained from the officers of Verifone.