Search Overlay

Prepaid Cards

asdf

Introduction

The Card service exposes features for managing cards related operations and eligible programs operations:

  • Get customer prepaid cards
  • Create a prepaid card
  • Update а card
  • Get prepaid card details
  • Retrieve customer eligible prepaid cards programs
  • Tokenize a prepaid card
  • Update card tokenization status

Use the following code to obtain an instance of CardService:

val cardService = Wallet.getInstance().getCardService()
import PaysafeWallet

let cardService = Wallet.instance.cardService

Get customer prepaid cards

Retrieve a list of all prepaid cards for the current customer. CardParameters are the parameters for filtering the customer's cards. Use include parameter to add additional information into the response: TOKENIZATIONS - include information about the mobile wallets tokenizations.

CardParameters

Parameter Type Description Example
cardType CardType Optional parameter to filter cards by card type. CardType.VIRTUAL / .virtual
limit Int Optional parameter to limit the number of results. 20
offset Int Optional parameter to specify the starting position, where 1 is the first page. 0
status List<CardStatus> / [Card.CardStatus] Optional parameter. List of card statuses which will be returned. Optional parameter, if not set all statuses will be returned. listOf(CardStatus.ACTIVE, CardStatus.CANCELLED) / [.active]
include List<CardIncludesParam> / [CardIncludesParam] Optional parameter. Include listed properties in the response. listOf(CardIncludesParam.TOKENIZATIONS) / [.tokenizations]

CardIncludesParam

Android iOS Description
TOKENIZATIONS .tokenizations Include additional information in card.

CardType

Enum class representing the type of a card.

Android iOS Description
PHYSICAL .physical The card is physical.
VIRTUAL .virtual The card is virtual.
UNKNOWN .unknown The type of the card is unknown or cannot be determined

CardStatus

Enum class representing the status of a card.

Android iOS Description
ACTIVE .active The card is currently active and can be used for transactions.
APPLIED .applied The card application is in progress or awaiting approval.
EXPIRED .expired The card has expired and is no longer valid for use.
DIGITAL .digital The card is in a digital format, such as a virtual or electronic card.
UNKNOWN .unknown The status of the card is unknown or cannot be determined

CardScheme

Enum class representing the scheme of a card.

Android iOS Description
MC .mastercard The card is Mastercard.
VISA .visa The card is Visa.
UNKNOWN .unknown The scheme of the card is unknown or cannot be determined.

The response is aCardList object which contains List<Card>/ [Card] and PagingResultMeta objects.

  • PagingResultMeta contains information about:
    • numberOfRecords - the total number of records available
    • limit - the maximum number of records per page
    • page - the current page number.
  • Card contains information about the card such as cardId, status, expiry, lastFour, bin, customerId, cardType, programName, currency, mobile,deliveryAddress,createdDate, accountId, scheme,activationDate, isPinSet, externalId, tokenizations
    • tokenizations contains object MobileWalletTokenizationList which contains list of MobileWalletTokenization with information such as dpanRef, walletId, walletType, status

MobileWalletType

Enum class representing the type of a mobile wallet.

Android iOS Description
APPLE_PAY .applePay The wallet type is Apple Pay.
GOOGLE_PAY .googlePay The wallet type is Google Pay.
SAMSUNG_PAY .samsungPay The wallet type is Samsung Pay.
UNKNOWN .unknown The wallet type is unknown or cannot be determined.

MobileWalletStatus

Enum class representing the tokenization status of a mobile wallet.

Android iOS Description
COMPLETED .completed The tokenization request is completed.
INITIATED .initiated The tokenization request is initiated.
UNKNOWN .unknown The type of the mobile wallet is unknown or cannot be determined.
val cardParameters = CardParameters(
    cardType = CardType.ACTIVE,
    limit = null,
    offset = null,
    status = listOf(CardStatus.ACTIVE, CardStatus.EXPIRED),
    include = listof(CardIncludesParam.TOKENIZATIONS)
)

try {
    val cards = cardService.getAll(cardParameters)
    Log.d(TAG, cards.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
let parameters = Wallet.CardParameters(cardType: .virtual,
                                       limit: nil,
                                       offset: nil,
                                       status: [.active, .expired],
                                       include: [.tokenizations])
cardService.getAll(parameters: parameters, completion: { result in
    switch result {
    case .success(let cards):
        // Display cards
    case .failure(let error):
        // Handle error
    }
})

You can achieve pagination by combining the limit and offset filters. For instance, implementing pagination with a page size of 2 results per page would involve configuring:

  • Page 1: limit=2, offset=0
  • Page 2: limit=2, offset=2
  • Page 3: limit=2, offset=4

Retrieve single prepaid card

Provides detailed information about specific card by cardId. The response is a single card object.

val cardId = "f16ba382-eb42-481a-b08f-c57bdc9aae24"
val include = listOf(CardIncludesParam.TOKENIZATIONS)

try {
    val card = cardService.get(cardId, include)
    Log.d(TAG, card.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
cardService.get(cardID: "f16ba382-eb42-481a-b08f-c57bdc9aae24", include: [.tokenizations], completion: { result in
    switch result {
    case .success(let card):
        // Display card
    case .failure(let error):
        // Handle error
    }
})

Create a prepaid card

Create a new Physical or Virtual prepaid card for a customer, based on the provided programName.

CardRequest

Parameter Type Description Example
programName String Required parameter. Program name retrieved from CardService. "SKRILL-VIRTUAL-MC-EEA"
currency String Required parameter. Currency code in three-letter format ("Alpha-3"). "EUR"
mobile String Optional parameter. If not provided, we will try to use the mobile phone provided during the customer onboarding. Mobile phone number must be in format "+1 123456789". "+1 123456789"
cardPin String Optional parameter. For EU Customers: The Card pin should be 4 digits. US customers must set their card PIN via a separate REST HTTP call. "1234"
externalId String Optional external identifier in merchant system. "a2322550-af91-417f-867e-681efad44b9d"
deliveryAddress DeliveryAddress Optional parameter. The DeliveryAddress object will be used for the PHYSICAL card delivery. It can be null in case of VIRTUAL card.
termsAndConditionsAccepted Boolean / Bool The field must be present for US customers. For other countries it is not required. True
eDisclosureAccepted Boolean / Bool The field must be present for US customers. For other countries it is not required. True

DeliveryAddress

Parameter Type Description Example
address1 String Required parameter mandatory for address. "Tsarigradsko Shose 73"
address2 String Optional parameter for address line 2 "Apartment 2C"
address3 String Optional parameter for address line 3. "Cityville, State 78901"
city String Required parameter for specifying the city. Max 30 characters: letters, spaces, hyphen and period. "Sofia"
countryCode String Required parameter in ISO-3166 Alpha 2, representing a country code "BG"
state String Optional parameter. For US Customers: 2,3-character state or province abbreviation. "NL"
postalCode String Required parameter. For EU customers: maximum length 16. For US customers: Pattern: ^[a-zA-Z0-9-\ ]*$ "1000"
val cardRequest = CardRequest(
    programName = "SKRILL-VIRTUAL-MC-EEA",
    currency = "BGN",
    mobile = "+1 123456789",
    cardPin = null,
    externalId = null,
    deliveryAddress = null
)

try {
    val card = cardService.create(cardRequest)
    Log.d(TAG, card.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
let request = Wallet.CreateCardRequest(programName: "SKRILL-VIRTUAL-MC-EEA",
                                       currency: "EUR",
                                       mobile: "+1 123456789",
                                       cardPin: nil,
                                       externalId: nil,
                                       deliveryAddress: nil)
cardService.create(request: request, completion: { result in
    switch result {
    case .success(let card):
        // Display created card
    case .failure(let error):
        // Handle error
    }
})

The parameters for PHYSICAL / .physical card application are the same, but you need to specify the deliveryAddress parameter.

val cardRequest = CardRequest(
    programName = "SKRILL-PHYSICAL-MC-EEA",
    currency = "BGN",
    mobile = "+1 123456789",
    cardPin = null,
    externalId = null,
    deliveryAddress = DeliveryAddress(
        address1 = "Tsarigradsko Shose 73",
        address2 = null,
        address3 = null,
        city = "Sofia",
        countryCode = "BG",
        state = null,
        postalCode = "1000"
    )
)

try {
    val card = cardService.create(cardRequest)
    Log.d(TAG, card.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
let request = Wallet.CreateCardRequest(programName: "SKRILL-PHYSICAL-MC-EEA",
                                       currency: "EUR",
                                       mobile: "+1 123456789",
                                       cardPin: nil,
                                       externalId: nil,
                                       deliveryAddress: .init(address1: "Tsarigradsko Shose 73",
                                                              address2: nil,
                                                              address3: nil,
                                                              city: "Sofia",
                                                              countryCode: "BG",
                                                              state: nil,
                                                              postalCode: "1000"))
cardService.create(request: request, completion: { result in
    switch result {
    case .success(let card):
        // Display created card
    case .failure(let error):
        // Handle error
    }
})

Update prepaid card status

The customer can change/update the status of their prepaid cards, and as a result, lock/unlock or cancel their prepaid card.

CardUpdateRequest

Parameter Type Description Example
status CardStatus Optional parameter containing information about the different card statuses. CardStatus.ACTIVE / .active
statusReason String Optional parameter for specifying the reason for card status change. "User Activate Card from LOCKED status"
pin String Optional parameter. The card pin should be 4 digits. "1243"
val cardUpdateRequest = CardUpdateRequest(
    status = Status.ACTIVE,
    statusReason = "User Activate Card from LOCKED status",
    pin = "1243"
)
val cardId = "f16ba382-eb42-481a-b08f-c57bdc9aae24"

try {
    val card = cardService.update(cardId, cardUpdateRequest)
    Log.d(TAG, card.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
let request = Wallet.CardUpdateRequest(status: .active,
                                       statusReason: "User Activate Card from LOCKED status",
                                       pin: "1234"
cardService.update(cardID: "f16ba382-eb42-481a-b08f-c57bdc9aae24", request: request, completion: { result in
    switch result {
    case .success(let card):
        // Display card
    case .failure(let error):
        // Handle error
    }
})

Get prepaid card details

Card sensitive information can be retrieved. The response contains card sensitive information such as pan, cvv, expiry, cardHolderName.

try {
    val cardSensitiveDetails = cardService.getDetails(cardId = "f16ba382-eb42-481a-b08f-c57bdc9aae24")
    Log.d(TAG, cardSensitiveDetails.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
cardService.getDetails(cardID: "f16ba382-eb42-481a-b08f-c57bdc9aae24", completion: { result in
    switch result {
    case .success(let cardDetails):
        // Display card details
    case .failure(let error):
        // Handle error
    }
})

Retrieve customer eligible prepaid cards programs

Retrieve eligible programs for a customer. The result list can be filtered by program type. If the customer is eligible for a Prepaid card, the response will contain a non-empty programs array. The number of cards that can be issued of a given type can be seen in the allowableCards field.

try {
    val eligiblePrograms = cardService.getPrograms()
    Log.d(TAG, eligiblePrograms.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
cardService.getPrograms(completion: { result in
    switch result {
    case .success(let programs):
        // Display prepaid programs
    case .failure(let error):
        // Handle error
    }
})

Tokenize a prepaid card

Tokenize given card for specific mobile wallet.

CardTokenizationRequest

Card Tokenization by which the client mobile application requests the needed info for card tokenization for a specific mobile wallet. Depending on the mobile wallet, device type, and card schema, some of the request fields are optional.

Parameter Type Description Example
walletType MobileWalletType Required parameter containing supported wallet types. MobileWalletType.GOOGLE_PAY / .applePay
clientDeviceId / clientDeviceID String Required for cards with VISA schema + Samsung/Google Pay. Not required for VISA + Apple Pay. "WNkcsfZPiKfa5PrH3jilkQYT"
clientWalletAccountId / clientWalletAccountID String Required for cards with VISA schema + Samsung/Google Pay. "40exmLiWV1iV55ZVstOAiMf7"
leafCertificate String Required for iOS. The leaf certificate returned by the wallet provider, that was signed using subordinateCertificate. Should be converted to hexadecimal (case insensitive) binary data of the certificate. If the certificate is in PEM encoding, then it should follow the typical standards for PEM. In particular, the tags -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- should be present and the Base64-encoded value should have lines of length 64.
subordinateCertificate String Required for iOS. The subordinate certificate returned by the wallet provider that was signed using the Wallet Provider’s Certificate Authority (CA) certificate. Should be converted to hexadecimal (case insensitive) binary data of the certificate. If the certificate is in PEM encoding, then it should follow the typical standards for PEM. In particular, the tags -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- should be present and the Base64-encoded value should have lines of length 64.
nonce String Required for iOS. Hexadecimal (case insensitive) nonce value returned by the Apple Pay SDK "w1koQg=="
nonceSignature String Required for iOS. Hexadecimal (case insensitive) nonce signature value returned by the Apple Pay SDK. "QF7lLU3rlO...iuscoJE9PdX"

The response is a CardTokenization object which contains the needed information in order specific card to be added to APPLE/GOOGLE Pay. Depending on the mobile device, some of the fields are optional.

  • opaquePaymentCard - it will be returned only for Google Pay.
  • encryptedPassData - will be returned only for Apple Pay.
  • ephemeralPublicKey - will be returned only for Apple Pay. Some other information that this object contains are: activationData,cardNetwork, tokenProvider, customer, cardLastDigits.
  • customer is an object containing information about specific card holder such as: address1, address2, address3, city, countryCode, state, postalCode, name, mobile

CardNetworkType

Enum class for representing cardNetwork.

Android iOS Description
CARD_NETWORK_VISA .cardNetworkVisa Visa card network.
CARD_NETWORK_MASTERCARD .cardNetworkMastercard Mastercard card network.
UNKNOWN .unknown The network of the card is unknown or cannot be determined.

CardTokenProvider

Enum class for representing tokenProvider.

Android iOS Description
TOKEN_PROVIDER_VISA .tokenProviderVisa Visa token provider.
TOKEN_PROVIDER_MASTERCARD .tokenProviderMastercard Mastercard token provider.
UNKNOWN .unknown The token provider is unknown or cannot be determined.
val cardId = "f16ba382-eb42-481a-b08f-c57bdc9aae24"
val cardTokenizationRequest = CardTokenizationRequest(
    walletType = MobileWalletType.GOOGLE_PAY,
    clientDeviceId = "WNkcsfZPiKfa5PrH3jilkQYT",
    clientWalletAccountId = "40exmLiWV1iV55ZVstOAiMf7"
)
try {
    val cardTokenizationResponse = cardService.tokenize(cardId, cardTokenizationRequest)
    Log.d(TAG, cardTokenizationResponse.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
let leafCertificate = "<base64 encoded certificate>"
let subordinateCertificate = "<base64 encoded certificate>"
let nonce = "<encoded value>"
let nonceSignature = "<encoded value>"

let request = Wallet.CardTokenizationRequest(leafCertificate: leafCertificate,
                                             subordinateCertificate: subordinateCertificate,
                                             nonce: nonce,
                                             nonceSignature: nonceSignature)
cardService.tokenize(cardID: "f16ba382-eb42-481a-b08f-c57bdc9aae24", request: request, completion: { result in
    switch result {
    case .success(let card):
      // Display card
    case .failure(let error):
      // Handle error
    }
})

Update card tokenization status

Updates card tokenization status by which tokenization can be marked as COMPLETED. Tokenization marked as COMPLETED means that the given card will be not able to be tokenized for the specific device and profile (in case of Google Pay).

MobileWalletTokenization

Contains information about card enrolment for specific Mobile Wallet

Parameter Type Description Example
dpanRef String Required parameter. dpan (Device Pan) reference. "DAPLMC00002125433c0c34a2821f4f86866e7576963baf8b"
walletId String Optional parameter. Wallet Id used only with Google Pay. "NMZlGi8-DezZZKaU06orvl0f"
walletType MobileWalletType Required parameter. The card pin should be 4 digits. MobileWalletType.GOOGLE_PAY / .applePay
status MobileWalletStatus Required parameter. The user agent of the device used for card creation. MobileWalletStatus.COMPLETED / .completed

The response is the updated MobileWallet object.

val mobileWalletRequest = MobileWallet(
    dpanRef = "DAPLMC00002125433c0c34a2821f4f86866e7576963baf8b",
    walletId = walletId,
    walletType = MobileWalletType.GOOGLE_PAY,
    status = MobileWalletStatus.COMPLETED
)
val cardId = "f16ba382-eb42-481a-b08f-c57bdc9aae24"
try {
    val mobileWalletResponse = cardService.updateTokenizationStatus(cardId, mobileWalletRequest)
    Log.d(TAG, mobileWalletResponse.toString())
} catch (exception: Exception) {
    Log.d(TAG, exception.toString())
}
let request = Wallet.MobileWallet(dpanRef: "DAPLMC00002125433c0c34a2821f4f86866e7572963baf8b",
                                  status: .completed)
cardService.updateTokenizationStatus(cardID: "f16ba382-eb42-481a-b08f-c57bdc9aae24", request: request, completion: { result in
    switch result {
    case .success(let card):
      // Display card
    case .failure(let error):
      // Handle error
    }
})

Apple card tokenzation

This section includes both sequence diagrams and a technical guide outlining the process of adding a card to Apple Wallet through the In-App Provisioning flow.

Prior to initiating the card addition implementation for Apple Wallet, it is essential to submit a request for access to Apple Pay in accordance with the latest guidelines provided in the Apple Developer documentation. For information on the prerequisites and required steps, please refer to the link provided below: https://developer.apple.com/documentation/passkit_apple_pay_and_wallet/apple_pay/setting_up_apple_pay/

Apple Pay button

"Add to Apple Wallet" Button should be only displayed if a card does not exist in Apple Wallet on either the iPhone or Apple Watch.

  • Verify device eligibility using canAddPaymentPass().
  • Check PKPassLibrary that card does not exists in passes() and remoteSecureElementPasses.
  • Display "Add to Apple Wallet" button using PKAddPassButton if conditions are met.
  • Tapping the button triggers In-App provisioning.

apple_prepaid_display_apple_button.svg

In-App provisioning

Once the user taps the 'Add to Apple Wallet' button, In-App Provisioning starts by initializing and presenting PKAddPaymentPassViewController.

Subsequently, Apple Wallet requests creation of PKAddPaymentPassRequest through PKAddPaymentPassViewControllerDelegate. The received Apple Public Certificates, along with nonce and nonceSignature, are used to make cardService.tokenize() request to the SDK.

Below code block demonstrates how CardTokenizationRequest is created from data returned by the delegate.

func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController,
                                  generateRequestWithCertificateChain certificates: [Data],
                                  nonce: Data,
                                  nonceSignature: Data,
                                  completionHandler handler: @escaping (PKAddPaymentPassRequest) -> Void) {
    let certificatesBase64EncodedString = certificates.map { $0.base64EncodedString() }
    let nonceBase64EncodedString = nonce.base64EncodedString()
    let nonceSignatureBase64EncodedString = nonceSignature.base64EncodedString()

    guard let leafCertificate = certificatesBase64EncodedString.first,
          let subordinateCertificate = certificatesBase64EncodedString.last else {
        // Handle error
        return
    }

    let tokenizationRequest = Wallet.CardTokenizationRequest(leafCertificate: leafCertificate,
                                                             subordinateCertificate: subordinateCertificate,
                                                             nonce: nonceBase64EncodedString,
                                                             nonceSignature: nonceSignatureBase64EncodedString)

    Wallet.instace.cardService.tokenize(cardID: card.cardID,
                                        request: tokenizationRequest,
                                        completion: { result in
        switch result {
        case .success(let cardTokenization):
            let pkAddPaymentPassRequest = PKAddPaymentPassRequest()
            pkAddPaymentPassRequest.activationData = Data(base64Encoded: cardTokenization.activationData)
            pkAddPaymentPassRequest.encryptedPassData = Data(base64Encoded: cardTokenization.encryptedPassData)
            pkAddPaymentPassRequest.ephemeralPublicKey = Data(base64Encoded: cardTokenization.ephemeralPublicKey)
        case .failure(let error):
            // Handle error
        }
    })
}

Apple Wallet further forwards the encryptedPassData and ephemeralPublicKey to the PNO (Payment Network Operator) or service provider, where validation checks are conducted. The PNO validates the activationData and performs final approval checks, subsequently sending the successful activation status to Apple Wallet. PKAddPaymentPassViewControllerDelegate notifies success/failure:

func addPaymentPassViewController(
    _ controller: PKAddPaymentPassViewController,
    didFinishAdding pass: PKPaymentPass?,
    error: Error?
)

Successful activation is communicated to the SDK with cardService.updateTokenizationStatus() which finalizes the process.

let request = Wallet.MobileWallet(dpanRef: tokenization.dpanRef,
                                  status: .completed)

cardService.updateTokenizationStatus(cardID: card.cardID,
                                     request: request,
                                     completion: { result in
    switch result {
    case .success(let card):
        // Display card
    case .failure(let error):
        // Handle error
    }
})

apple_prepaid_in_app_provisioning.svg

Google card tokenzation

This section offers sequence diagrams and a detailed technical step-by-step guide for integrating card tokenization into Google Wallet using Android Push Provisioning API.

Card tokenization involves generating a secure digital replica of an existing physical or virtual card. This replica is subsequently integrated into a token network, such as Google Pay. For Google Pay, token provisioning can occur either manually, where a tokenization request is initiated from Google Wallet, or through push provisioning, where the request originates from your application.

Before initiating the card tokenization process on Google Wallet, the first step is creating a Google account if one has not already been created. After setting up your Google account, you can initiate the access request through this form, as gaining access involves submitting a request to Google Android Push Provisioning API.

After obtaining access, you can download and import the latest version of play-services-tapandpay.aar enabling you to use the TapAndPay SDK. TapAndPay SDK is a library developed by Google which streamlines the necessary calls to integrate with Google Wallet.

Google button display

The initial step is to display the Google button with the appropriate logo and dimensions. Google Pay button should be only displayed if a card does not exist in Google Pay/Wallet. Further information about this can be found in the official documentation provided by Google once access to the page is granted.

The sequence diagram below illustrates the essential checks required to initialize and display the Google button, in conjunction with the Paysafe mobile SDK, Android OS, and TapAndPay SDK.

google_prepaid_display_google_button.svg

Google button click

After completing the aforementioned steps to display and initialize the button, a subsequent click on the button will initiate one of the three specified flows below.

Push Tokenization

This flow will be initiated under two conditions: firstly, if the attempt to list tokens from TapAndPay SDK results in a failure with exception code TapAndPayStatusCode.TAP_AND_PAY_NAOCTIVE_WALLET and secondly, if there is no match between the tokens retrieved from TapAndPay SDK and the tokens retrived from Paysafe Mobile SDK.

The following sequence diagram outlines the necessary steps for Push Tokenization.

google_prepaid_push_tokenization.svg

Manual Tokenization

This flow is initiated when listing the tokens affiliated with a particular wallet and discovering a token in the TapAndPay.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION state related to the selected card.

When a token is in TapAndPay.TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION state, manual verification becomes necessary as an additional step to authenticate a card for a specific user.

The following sequence diagram outlines the necessary steps for Manual Tokenization.

google_prepaid_manual_tokenization.svg

Create wallet

This flow is initiated when no wallet has been previously created on the device. It can be triggered either through the Push Tokenization or Manual Tokenization flows, where a call to activeWalletId and stableHardwareId may throw an exception in the absence of a wallet.

The following sequence diagram outlines the necessary steps to add a wallet to a device.

google_prepaid_create_wallet.svg

On this Page