Android API

The following views are available with the AffiniPay mobile SDK:

Amount Selection (optional)

The AmountSelectionFragment is a view that allows the user to input a dollar amount that is then returned to the calling activity or fragment.

Input

None

Output

The calling activity will receive an AmountResults object with the following member:

ParameterTypeDescription
amountstringThe requested charge amount given in US cents, unformatted. The AffiniPay Payment Gateway expects the charge in the same format. For example, USD $2.46 would be returned as “246”.

Interface

This interface should be implemented by the object that will receive the AmountResult object (typically by the activity or fragment that is launching the AmountSelectionFragment).

interface AmountRequester {

/**
 * @param amountResults - amountResults.amount will return the requested charge amount
 * given in US cents, unformatted. The AffiniPay Gateway expects the charge in the
 * same format. For example, USD $2.46 would be returned as "246".
 */
  fun onAmountReceived(amountResults: AmountResults)
}

Example: Obtain AmountSelectionFragment from ViewProvider

val fragmentTransaction = fragmentManager.beginTransaction()
val amountSelectionFragment = ViewProvider.getAmountSelectionView()
fragmentTransaction.replace(R.id.fragment_container, amountSelectionFragment)
fragmentTransaction.commit()

Example: Implement the AmountRequester interface

override fun onAmountReceived(amountResult: AmountResult) {
  amount = amountResult.amount
  val requiredFieldTypes = arrayListOf(CustomerInfoType.EMAIL, CustomerInfoType.POSTAL_CODE, CustomerInfoType.ADDRESS1)
  val params = CustomerInfoParams(requiredFieldTypes)
  goToScreen(ViewProvider.getCustomerInfoView(params))
}

private fun goToScreen(newView: Fragment) {
  val fragmentTransaction = fragmentManager.beginTransaction()
  fragmentTransaction.replace(R.id.fragment_container, newView).addToBackStack(newView.tag)
  fragmentTransaction.commit()
}

Screen highlights

  1. The unformatted amount is passed to the AmountRequester interface.
  2. An error message shows when an invalid amount is entered.
  3. The Confirm button is enabled after a valid amount is entered. The unformatted amount is passed to the onAmountReceived callback method when the Confirm button is tapped.

The CustomerDetailsInputFragment is a view that allows the user to input specific details about a customer (such as name, address, and email) and returns those details to the calling activity or fragment.

Input

ParameterTypeDescription
mandatoryFieldsArrayListCustomerInfoType is an enum specifying all possible customer input fields.
- NAME
- ADDRESS1
- PHONE*
- EMAIL*
- STATE
- COUNTRY
- POSTAL_CODE*
- REFERENCE
- CITY
*These fields have some validation that must be passed if any value is entered. The validation must be passed even if the field is not required.
customerPrefillCustomerInfoAn optional parameter that enables you to pre-fill the customer form fields with your own values. Note that when you pre-fill the country, you should submit either the ISO 3166-1 alpha-2 code or the English short country name officially used by the ISO 3166 Maintenance Agency (ISO 3166/MA).

Output

The calling activity will receive a CustomerInfoResult object with the following member:

ParameterTypeDescription
customerInfoCustomerInfoDetails about the customer.

The CustomerInfo object will have the following members:

ParameterTypeDescription
namestringThe name of the customer.
emailstringThe email address of the customer.
address1stringThe street address of the customer.
address2stringApt/Unit of the customer.
citystringThe city of the customer’s billing address.
statestringThe U.S. state or Canadian province of the customer’s billing address.
countrystringThe country of the customer’s billing address.
postalCodestringThe postal code of the customer’s billing address.
phonestringThe phone number of the customer.
referencestringA number used for internal tracking, such as the customer’s account number or the transaction ID.

Interface

This interface should be implemented by the activity or fragment that is launching the CustomerInfoFragment.

interface CustomerInfoRequester {

  fun onCustomerInfoReceived(customerInfoResult: CustomerInfoResult)

}

If no pre-fill information is going to be passed, use an empty CustomerInfo object:

var ciparams = CustomerInfoParams(list, CustomerInfo())

Example: Obtain CustomerInfoFragment from ViewProvider

val mandatoryFields = arrayListOf(CustomerInfoType.NAME, CustomerInfoType.EMAIL, CustomerInfoType.POSTAL_CODE,
        CustomerInfoType.CITY, CustomerInfoType.PHONE, CustomerInfoType.REFERENCE, CustomerInfoType.ADDRESS1,
        CustomerInfoType.STATE, CustomerInfoType.COUNTRY)
val customerInfo = CustomerInfo(
        name = "AffiniPay User",
        email = "user@affinipay.com",
        phone = "123-456-7890",
        reference = "A Reference",
        address1 = "3700 N Capital of Texas Hwy",
        address2 = "#300",
        city = "Austin",
        postalCode = "78746",
        country = "US"
)
val params = CustomerInfoParams(mandatoryFields, customerInfo)
val fragment = ViewProvider.getCustomerInfoView(params)
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(R.id.fragment_container, fragment)
fragmentTransaction.commit()

Example: Implement the CustomerInfoRequester interface

override fun onCustomerInfoReceived(customerInfoResult: CustomerInfoResult) {
  goToScreen(ViewProvider.getCardEntryView(ChargeParams(customerInfoResult.customerInfo, publicKey, amount)))
}

private fun goToScreen(newView: Fragment) {
  val fragmentTransaction = fragmentManager.beginTransaction()
  fragmentTransaction.replace(R.id.fragment_container, newView).addToBackStack(newView.tag)
  fragmentTransaction.commit()
}

Screen highlights

  1. Field validation indicates whether field input is formatted correctly. If it's not, it's marked as invalid.
  2. Required fields are determined by the mandatoryFields parameter and marked with an asterisk.
  3. Optional fields are determined by the mandatoryFields parameter.
  1. The Next button is enabled only after all required fields are filled and all fields are formatted properly. If the button is disabled, an error message indicates the reason why. After the Next button is tapped, customer details are passed to the onCustomerInfoReceived callback method.

Card Entry (required)

The CardEntryFragment is a view that allows the user to input credit/debit card information manually or using the AffiniPay card reader. A token that is returned from the AffiniPay Payment Gateway to the calling activity or fragment can then be used to make a charge.

Note: When the AffiniPay card reader is used to make a chip scanning (EMV) charge, you must submit a signature to finalize the charge. You can obtain a signature using either the mobile SDK signature screen or your own screen.

Input

The calling object will pass a ChargeParams object with the following parameters:

ParameterTypeDescription
customerInfoCustomerInfoCustomer contact/billing details and used to create a one-time token.
publicKeystringThe public key for your account obtained from OAuth login used to create a one-time token.
amountstringThe requested charge amount given in US cents, unformatted. The AffiniPay Payment Gateway expects the charge in the same format. For example, USD $2.46 would be returned as “246”. This amount will be displayed (formatted) in the CardInputFragment

Output

The calling activity or fragment will receive a ChargeResult object with the following members:

ParameterTypeDescription
oneTimeTokenstringA temporary token given by the AffiniPay Payment Gateway that can be used to create a charge.
amountstringThe requested charge amount given in US cents, unformatted. The AffiniPay Payment Gateway expects the charge in the same format. For example, USD $2.46 would be returned as “246”.
pointOfSalePointOfSaleAdditional parameters that describe the payment and verification method.
paymentDataSourcestringThe reason for payment failing to use EMV (Chip Scanning) and falling back to Magstripe (Swipe) instead.

Interface

This interface should be implemented by the activity or fragment that is launching the CardInputFragment.

interface ChargeRequester {

  fun onEMVChargeDataReceived(emvChargeResult: ChargeResult)

  fun onSwipeChargeDataReceived(swipeChargeResult: ChargeResult)

  fun onManualChargeDataReceived(manualChargeResult: ChargeResult)
}

Example: Obtain CardEntryFragment from ViewProvider

val customerInfo = CustomerInfo()
customerInfo.name = "John Doe"
customerInfo.address = "123 Easy St"
customerInfo.email = "jdoe@affinipay.com"
val chargeParams = ChargeParams(customerInfo, publicKey, amount)
val fragment = ViewProvider.getCardEntryView(chargeParams)
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(R.id.fragment_container, fragment)
fragmentTransaction.commit()

Example: Implement the ChargeRequester interface

override fun onManualChargeDataReceived(manualChargeResult: ChargeResult) {
  chargeModel.makeCharge(publicKey, accountId, manualChargeResult.oneTimeToken, manualChargeResult.amount).subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread()).subscribe({
    charge ->
    fragment.completionCallback(true)
    handleChargeCompletedReceipt(charge)
  }, {
    error ->
    fragment.completionCallback(false)
    print(error.message)
  })
}

override fun onSwipeChargeDataReceived(swipeChargeResult: ChargeResult) {
  chargeModel.makeCharge(publicKey, accountId, swipeChargeResult.oneTimeToken, swipeChargeResult.amount).subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread()).subscribe({
    charge ->
    fragment.completionCallback(true)
    handleChargeCompletedReceipt(charge)
  }, {
    error ->
    fragment.completionCallback(false)
    print(error.message)
  })
}

override fun onEMVChargeDataReceived(emvChargeResult: ChargeResult) {
  chargeModel.makeEMVCharge(publicKey, accountId, emvChargeResult.oneTimeToken, emvChargeResult.amount, emvChargeResult.paymentDataSource,
      emvChargeResult.pointOfSale as PointOfSale).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe({
    charge ->
    fragment.completionCallback(true)
    handleChargeCompletedReceipt(charge)
  }, {
    error ->
    fragment.completionCallback(false)
    print(error.message)
  })
}

fun handleChargeCompletedReceipt(charge: Charge) {
  val chargeId = charge.chargeDetails?.id
  val dialog = AlertDialog.Builder(this)
  dialog.setTitle("Charge Receipt")
      .setMessage(charge.toString())
      .setPositiveButton("Sign", { _: DialogInterface, _: Int ->
        val signIntent = Intent(this, SignatureActivity::class.java)
        signIntent.putExtra(SignatureActivity.ARG_PUBLIC_KEY, publicKey)
        signIntent.putExtra(SignatureActivity.ARG_ACCOUNT_ID, accountId)
        signIntent.putExtra(SignatureActivity.ARG_CHARGE_ID, chargeId)
        signIntent.putExtra(SignatureFragment.ARG_AMOUNT, amount)
        startActivity(signIntent)
      }).show()
}

Note: Upon receiving a response from your server, you should notify the SDK via the completionCallback method on the CardEntryFragment (sending true for success or false for failure). This will allow the view to show an appropriate success or failure message. If the SDK doesn’t receive any response from the callback, it will automatically assume the charge has failed after a certain amount of time has passed.

Screen highlights

  1. The card number, expiration, and CVV fields are for manual card entry.
  2. Info and error messages give information about card reader, input validation, and other errors.
  3. For manual entry, the payment token is generated and then sent to the onManualChargeDataReceived callback method after this button is tapped. The button is disabled if there are any input validation errors.

Signature (optional)

The SignatureFragment is a view that allows the user to sign an AffiniPay Payment Gateway charge.

Input

The calling activity or fragment will need to provide a SignatureParams object which will contain the following members:

ParameterTypeDescription
accountNamestringThe name of the account that is being paid. This name will be displayed in the Signature view.
amountstringThe requested charge amount given in US cents, unformatted. The AffiniPay Payment Gateway expects the charge in the same format. For example, USD $2.46 would be returned as “246”. This amount will be displayed (formatted) in the Signature view.

Output

The calling activity or fragment will receive a SignatureResult object with the following member:

ParameterTypeDescription
signaturestringThe signature of an authorized business representative. Uses default jQuery.signaturePad JSON format. Example: [{“lx”:5,”ly”:51,”mx”:5,”my”:50}, {“lx”:5,”ly”:49,”mx”:5,”my”:51}]

Interface

This interface should be implemented by the activity or fragment that is launching the SignatureFragment.

interface SignatureRequester {

  fun onSignatureReceived(signatureResult: SignatureResult)

}

Example: Obtain SignatureFragment from ViewProvider

val amount = "246"
val accountName = "Central Texas Association"
val fragment = ViewProvider.getSignatureView(SignatureParams(accountName, amount))
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(R.id.fragment_container, fragment)
fragmentTransaction.commit()

Example: Implement the SignatureRequester interface

override fun onSignatureReceived(signatureResult: SignatureResult) {

  val chargeId = intent.extras.getString(ARG_CHARGE_ID)
  val accountId = intent.extras.getString(ARG_ACCOUNT_ID)
  val publicKey = intent.extras.getString(ARG_PUBLIC_KEY)

  chargeModel.addSignature(chargeId, accountId, signatureResult.signature, publicKey).subscribe({

    val receiptIntent = Intent(this, ReceiptActivity::class.java)
    receiptIntent.putExtra(ReceiptActivity.ARG_AMOUNT, intent.getStringExtra(SignatureFragment.ARG_AMOUNT))
    startActivity(receiptIntent)
  })
}

Screen highlights

  1. The display name and formatted payment amount are passed in as part of the SignatureParams object.
  2. The touchable signature area.
  3. After the Done button is tapped, the raw coordinates of the signature are passed to the onSignatureReceived callback method to be saved in any format.